@ciderpress/ui 1.0.0-rc.1

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 (428) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/0~142.js +2 -0
  4. package/dist/0~164.js +2 -0
  5. package/dist/0~2.js +2 -0
  6. package/dist/0~225.js +2 -0
  7. package/dist/0~288.js +2 -0
  8. package/dist/0~299.js +2 -0
  9. package/dist/0~3.js +2 -0
  10. package/dist/0~301.js +2 -0
  11. package/dist/0~311.js +2 -0
  12. package/dist/0~326.js +2 -0
  13. package/dist/0~40.js +2 -0
  14. package/dist/0~43.js +2 -0
  15. package/dist/0~433.js +2 -0
  16. package/dist/0~453.js +2 -0
  17. package/dist/0~457.js +2 -0
  18. package/dist/0~497.js +2 -0
  19. package/dist/0~511.js +2 -0
  20. package/dist/0~603.js +2 -0
  21. package/dist/0~616.js +2 -0
  22. package/dist/0~659.js +2 -0
  23. package/dist/0~670.js +2 -0
  24. package/dist/0~687.js +2 -0
  25. package/dist/0~706.js +2 -0
  26. package/dist/0~729.js +2 -0
  27. package/dist/0~768.js +2 -0
  28. package/dist/0~819.js +2 -0
  29. package/dist/0~830.js +2 -0
  30. package/dist/0~854.js +2 -0
  31. package/dist/0~863.js +2 -0
  32. package/dist/0~879.js +2 -0
  33. package/dist/0~96.js +2 -0
  34. package/dist/0~97.js +2 -0
  35. package/dist/components/FileTree/FileTree.css +90 -0
  36. package/dist/components/FileTree/FileTree.d.ts +7 -0
  37. package/dist/components/FileTree/FileTree.js +531 -0
  38. package/dist/components/FileTree/FileTreeItem.d.ts +8 -0
  39. package/dist/components/FileTree/RemoteSvgIcon.d.ts +11 -0
  40. package/dist/components/FileTree/index.d.ts +4 -0
  41. package/dist/components/folder-icons.d.ts +32 -0
  42. package/dist/components/languages.d.ts +7 -0
  43. package/dist/components/tree-parser/tree-parser.d.ts +12 -0
  44. package/dist/components/tree-parser/types.d.ts +11 -0
  45. package/dist/head/css/loader-apple.css +1 -0
  46. package/dist/head/css/loader-backdrop.css +1 -0
  47. package/dist/head/css/loader-dots.css +1 -0
  48. package/dist/head/css/themes/amber.css +1 -0
  49. package/dist/head/css/themes/arcade.css +1 -0
  50. package/dist/head/css/themes/grannysmith.css +1 -0
  51. package/dist/head/css/themes/honeycrisp.css +1 -0
  52. package/dist/head/css/themes/midnight.css +1 -0
  53. package/dist/head/css/themes/mulled.css +1 -0
  54. package/dist/head/js/loader-dots.js +1 -0
  55. package/dist/head/js/vscode-nav.js +1 -0
  56. package/dist/index.d.ts +43 -0
  57. package/dist/index.mjs +40 -0
  58. package/dist/node.d.ts +81 -0
  59. package/dist/node.mjs +17762 -0
  60. package/dist/plugins/mermaid/MermaidRenderer.tsx +480 -0
  61. package/dist/plugins/mermaid/mermaid.css +199 -0
  62. package/dist/theme/components/announcement/announcement-bar.css +103 -0
  63. package/dist/theme/components/announcement/announcement-bar.tsx +173 -0
  64. package/dist/theme/components/ask-ai/ask-ai-button.css +52 -0
  65. package/dist/theme/components/ask-ai/ask-ai-button.tsx +56 -0
  66. package/dist/theme/components/content-footer/content-footer-portal.tsx +70 -0
  67. package/dist/theme/components/content-footer/feedback.css +47 -0
  68. package/dist/theme/components/content-footer/feedback.tsx +96 -0
  69. package/dist/theme/components/content-footer/meta-actions.css +25 -0
  70. package/dist/theme/components/content-footer/meta-actions.tsx +57 -0
  71. package/dist/theme/components/content-footer/page-pager.css +61 -0
  72. package/dist/theme/components/content-footer/page-pager.tsx +110 -0
  73. package/dist/theme/components/edit-source-button.tsx +97 -0
  74. package/dist/theme/components/footer/site-footer.css +179 -0
  75. package/dist/theme/components/footer/site-footer.tsx +115 -0
  76. package/dist/theme/components/home/cta.css +67 -0
  77. package/dist/theme/components/home/cta.tsx +77 -0
  78. package/dist/theme/components/home/feature-card.css +52 -0
  79. package/dist/theme/components/home/feature-card.tsx +131 -0
  80. package/dist/theme/components/home/feature.tsx +79 -0
  81. package/dist/theme/components/home/hero-demo.css +66 -0
  82. package/dist/theme/components/home/hero-demo.tsx +46 -0
  83. package/dist/theme/components/home/hero.css +96 -0
  84. package/dist/theme/components/home/hero.tsx +111 -0
  85. package/dist/theme/components/home/layout.tsx +183 -0
  86. package/dist/theme/components/home/page-rail.css +21 -0
  87. package/dist/theme/components/home/page-rail.tsx +19 -0
  88. package/dist/theme/components/home/split.css +148 -0
  89. package/dist/theme/components/home/split.tsx +120 -0
  90. package/dist/theme/components/home/trust-strip.css +33 -0
  91. package/dist/theme/components/home/trust-strip.tsx +43 -0
  92. package/dist/theme/components/home/workspaces.tsx +71 -0
  93. package/dist/theme/components/nav/branch-tag.css +54 -0
  94. package/dist/theme/components/nav/branch-tag.tsx +101 -0
  95. package/dist/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
  96. package/dist/theme/components/nav/ciderpress-docs-bar.css +505 -0
  97. package/dist/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
  98. package/dist/theme/components/nav/ciderpress-header.css +172 -0
  99. package/dist/theme/components/nav/ciderpress-header.tsx +113 -0
  100. package/dist/theme/components/nav/ciderpress-layout-context.tsx +49 -0
  101. package/dist/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
  102. package/dist/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
  103. package/dist/theme/components/nav/ciderpress-nav-menu.css +130 -0
  104. package/dist/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
  105. package/dist/theme/components/nav/ciderpress-nav-search.css +73 -0
  106. package/dist/theme/components/nav/ciderpress-nav-search.tsx +55 -0
  107. package/dist/theme/components/nav/ciderpress-nav-social-links.css +35 -0
  108. package/dist/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
  109. package/dist/theme/components/nav/floating-branch-indicator.css +106 -0
  110. package/dist/theme/components/nav/floating-branch-indicator.tsx +109 -0
  111. package/dist/theme/components/nav/layout.tsx +268 -0
  112. package/dist/theme/components/nav/mobile-nav-cta.tsx +79 -0
  113. package/dist/theme/components/nav/nav-divider.css +15 -0
  114. package/dist/theme/components/nav/nav-divider.tsx +19 -0
  115. package/dist/theme/components/nav/nav-logo.css +42 -0
  116. package/dist/theme/components/nav/nav-logo.tsx +262 -0
  117. package/dist/theme/components/nav/theme-switcher.css +92 -0
  118. package/dist/theme/components/nav/theme-switcher.tsx +298 -0
  119. package/dist/theme/components/nav/topbar-cta.css +45 -0
  120. package/dist/theme/components/nav/topbar-cta.tsx +39 -0
  121. package/dist/theme/components/nav/variant-toggle.css +70 -0
  122. package/dist/theme/components/nav/variant-toggle.tsx +83 -0
  123. package/dist/theme/components/nav/version-chip.css +31 -0
  124. package/dist/theme/components/nav/version-chip.tsx +45 -0
  125. package/dist/theme/components/nav/vscode-tag.css +32 -0
  126. package/dist/theme/components/nav/vscode-tag.tsx +20 -0
  127. package/dist/theme/components/openapi/code-sample.tsx +341 -0
  128. package/dist/theme/components/openapi/copy-markdown-button.tsx +41 -0
  129. package/dist/theme/components/openapi/icons.tsx +45 -0
  130. package/dist/theme/components/openapi/index.ts +6 -0
  131. package/dist/theme/components/openapi/method-badge.tsx +24 -0
  132. package/dist/theme/components/openapi/openapi.css +665 -0
  133. package/dist/theme/components/openapi/operation.tsx +200 -0
  134. package/dist/theme/components/openapi/overview.tsx +207 -0
  135. package/dist/theme/components/openapi/parameters-table.tsx +149 -0
  136. package/dist/theme/components/openapi/request-body.tsx +90 -0
  137. package/dist/theme/components/openapi/response-list.tsx +112 -0
  138. package/dist/theme/components/openapi/schema-viewer.tsx +277 -0
  139. package/dist/theme/components/openapi/security-badges.tsx +63 -0
  140. package/dist/theme/components/openapi/spec-utils.ts +122 -0
  141. package/dist/theme/components/shared/accordion.css +118 -0
  142. package/dist/theme/components/shared/accordion.stories.tsx +96 -0
  143. package/dist/theme/components/shared/accordion.tsx +191 -0
  144. package/dist/theme/components/shared/brand-logo.stories.tsx +49 -0
  145. package/dist/theme/components/shared/brand-mark.stories.tsx +53 -0
  146. package/dist/theme/components/shared/browser-window.css +1 -0
  147. package/dist/theme/components/shared/browser-window.stories.tsx +100 -0
  148. package/dist/theme/components/shared/browser-window.tsx +2 -0
  149. package/dist/theme/components/shared/card.stories.tsx +50 -0
  150. package/dist/theme/components/shared/card.tsx +35 -0
  151. package/dist/theme/components/shared/ciderpress-logo.tsx +93 -0
  152. package/dist/theme/components/shared/ciderpress-mark.tsx +77 -0
  153. package/dist/theme/components/shared/color.css +56 -0
  154. package/dist/theme/components/shared/color.stories.tsx +47 -0
  155. package/dist/theme/components/shared/color.tsx +69 -0
  156. package/dist/theme/components/shared/columns.css +37 -0
  157. package/dist/theme/components/shared/columns.stories.tsx +91 -0
  158. package/dist/theme/components/shared/columns.tsx +50 -0
  159. package/dist/theme/components/shared/desktop-window.css +339 -0
  160. package/dist/theme/components/shared/desktop-window.tsx +535 -0
  161. package/dist/theme/components/shared/field.css +158 -0
  162. package/dist/theme/components/shared/field.stories.tsx +100 -0
  163. package/dist/theme/components/shared/field.tsx +186 -0
  164. package/dist/theme/components/shared/frame.css +39 -0
  165. package/dist/theme/components/shared/frame.stories.tsx +49 -0
  166. package/dist/theme/components/shared/frame.tsx +76 -0
  167. package/dist/theme/components/shared/icon.stories.tsx +90 -0
  168. package/dist/theme/components/shared/icon.tsx +41 -0
  169. package/dist/theme/components/shared/prompt.css +178 -0
  170. package/dist/theme/components/shared/prompt.stories.tsx +57 -0
  171. package/dist/theme/components/shared/prompt.tsx +369 -0
  172. package/dist/theme/components/shared/resolve-card-icon.ts +28 -0
  173. package/dist/theme/components/shared/section-card.stories.tsx +51 -0
  174. package/dist/theme/components/shared/section-card.tsx +44 -0
  175. package/dist/theme/components/shared/section-grid.stories.tsx +46 -0
  176. package/dist/theme/components/shared/section-grid.tsx +15 -0
  177. package/dist/theme/components/shared/status-badge.css +37 -0
  178. package/dist/theme/components/shared/status-badge.stories.tsx +61 -0
  179. package/dist/theme/components/shared/status-badge.tsx +74 -0
  180. package/dist/theme/components/shared/steps.css +88 -0
  181. package/dist/theme/components/shared/steps.stories.tsx +68 -0
  182. package/dist/theme/components/shared/steps.tsx +100 -0
  183. package/dist/theme/components/shared/tech-icon-table.stories.tsx +29 -0
  184. package/dist/theme/components/shared/tech-icon-table.tsx +71 -0
  185. package/dist/theme/components/shared/tech-tag.stories.tsx +40 -0
  186. package/dist/theme/components/shared/tech-tag.tsx +31 -0
  187. package/dist/theme/components/shared/theme-color-palette.css +80 -0
  188. package/dist/theme/components/shared/theme-color-palette.stories.tsx +52 -0
  189. package/dist/theme/components/shared/theme-color-palette.tsx +275 -0
  190. package/dist/theme/components/shared/tooltip.css +69 -0
  191. package/dist/theme/components/shared/tooltip.stories.tsx +72 -0
  192. package/dist/theme/components/shared/tooltip.tsx +77 -0
  193. package/dist/theme/components/sidebar/framework-picker.css +77 -0
  194. package/dist/theme/components/sidebar/framework-picker.tsx +78 -0
  195. package/dist/theme/components/sidebar/sidebar-filter.test.ts +140 -0
  196. package/dist/theme/components/sidebar/sidebar-filter.ts +79 -0
  197. package/dist/theme/components/sidebar/sidebar-links.css +102 -0
  198. package/dist/theme/components/sidebar/sidebar-links.tsx +122 -0
  199. package/dist/theme/components/sidebar/sidebar-promo.css +42 -0
  200. package/dist/theme/components/sidebar/sidebar-promo.tsx +52 -0
  201. package/dist/theme/components/sidebar/sidebar-scope.tsx +151 -0
  202. package/dist/theme/components/sidebar/sidebar-toggle.css +181 -0
  203. package/dist/theme/components/sidebar/sidebar-toggle.tsx +127 -0
  204. package/dist/theme/components/theme-provider.tsx +637 -0
  205. package/dist/theme/components/workspaces/card.css +151 -0
  206. package/dist/theme/components/workspaces/card.tsx +166 -0
  207. package/dist/theme/components/workspaces/grid.tsx +62 -0
  208. package/dist/theme/css.d.ts +1 -0
  209. package/dist/theme/env.d.ts +12 -0
  210. package/dist/theme/fonts/GeistMono-Variable.woff2 +0 -0
  211. package/dist/theme/fonts/GeistPixel-Square.woff2 +0 -0
  212. package/dist/theme/fonts/GeistSans-Variable.woff2 +0 -0
  213. package/dist/theme/hooks/use-ciderpress.ts +61 -0
  214. package/dist/theme/hooks/use-nav-items.ts +76 -0
  215. package/dist/theme/icons/index.ts +2 -0
  216. package/dist/theme/icons/tech-map.ts +228 -0
  217. package/dist/theme/index.tsx +180 -0
  218. package/dist/theme/lib/read-social-links.ts +27 -0
  219. package/dist/theme/lib/route-link.tsx +126 -0
  220. package/dist/theme/lib/safe-url.test.ts +0 -0
  221. package/dist/theme/lib/safe-url.ts +68 -0
  222. package/dist/theme/lib/theme-favicon.ts +125 -0
  223. package/dist/theme/lib/user-config-stub.ts +12 -0
  224. package/dist/theme/styles/layers.css +32 -0
  225. package/dist/theme/styles/overrides/badge.css +26 -0
  226. package/dist/theme/styles/overrides/content-footer.css +80 -0
  227. package/dist/theme/styles/overrides/details.css +61 -0
  228. package/dist/theme/styles/overrides/fonts.css +32 -0
  229. package/dist/theme/styles/overrides/home-card.css +133 -0
  230. package/dist/theme/styles/overrides/home.css +243 -0
  231. package/dist/theme/styles/overrides/rail.css +337 -0
  232. package/dist/theme/styles/overrides/rspress.css +62 -0
  233. package/dist/theme/styles/overrides/scrollbar.css +25 -0
  234. package/dist/theme/styles/overrides/section-card.css +114 -0
  235. package/dist/theme/styles/overrides/sidebar.css +144 -0
  236. package/dist/theme/styles/overrides/tokens.css +288 -0
  237. package/dist/theme/styles/overrides/vscode.css +88 -0
  238. package/dist/theme/styles/themes/amber.css +545 -0
  239. package/dist/theme/styles/themes/arcade-fx.css +366 -0
  240. package/dist/theme/styles/themes/arcade.css +273 -0
  241. package/dist/theme/styles/themes/grannysmith.css +545 -0
  242. package/dist/theme/styles/themes/honeycrisp.css +545 -0
  243. package/dist/theme/styles/themes/midnight.css +273 -0
  244. package/dist/theme/styles/themes/mulled.css +817 -0
  245. package/package.json +103 -0
  246. package/src/theme/components/announcement/announcement-bar.css +103 -0
  247. package/src/theme/components/announcement/announcement-bar.tsx +173 -0
  248. package/src/theme/components/ask-ai/ask-ai-button.css +52 -0
  249. package/src/theme/components/ask-ai/ask-ai-button.tsx +56 -0
  250. package/src/theme/components/content-footer/content-footer-portal.tsx +70 -0
  251. package/src/theme/components/content-footer/feedback.css +47 -0
  252. package/src/theme/components/content-footer/feedback.tsx +96 -0
  253. package/src/theme/components/content-footer/meta-actions.css +25 -0
  254. package/src/theme/components/content-footer/meta-actions.tsx +57 -0
  255. package/src/theme/components/content-footer/page-pager.css +61 -0
  256. package/src/theme/components/content-footer/page-pager.tsx +110 -0
  257. package/src/theme/components/edit-source-button.tsx +97 -0
  258. package/src/theme/components/footer/site-footer.css +179 -0
  259. package/src/theme/components/footer/site-footer.tsx +115 -0
  260. package/src/theme/components/home/cta.css +67 -0
  261. package/src/theme/components/home/cta.tsx +77 -0
  262. package/src/theme/components/home/feature-card.css +52 -0
  263. package/src/theme/components/home/feature-card.tsx +131 -0
  264. package/src/theme/components/home/feature.tsx +79 -0
  265. package/src/theme/components/home/hero-demo.css +66 -0
  266. package/src/theme/components/home/hero-demo.tsx +46 -0
  267. package/src/theme/components/home/hero.css +96 -0
  268. package/src/theme/components/home/hero.tsx +111 -0
  269. package/src/theme/components/home/layout.tsx +183 -0
  270. package/src/theme/components/home/page-rail.css +21 -0
  271. package/src/theme/components/home/page-rail.tsx +19 -0
  272. package/src/theme/components/home/split.css +148 -0
  273. package/src/theme/components/home/split.tsx +120 -0
  274. package/src/theme/components/home/trust-strip.css +33 -0
  275. package/src/theme/components/home/trust-strip.tsx +43 -0
  276. package/src/theme/components/home/workspaces.tsx +71 -0
  277. package/src/theme/components/nav/branch-tag.css +54 -0
  278. package/src/theme/components/nav/branch-tag.tsx +101 -0
  279. package/src/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
  280. package/src/theme/components/nav/ciderpress-docs-bar.css +505 -0
  281. package/src/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
  282. package/src/theme/components/nav/ciderpress-header.css +172 -0
  283. package/src/theme/components/nav/ciderpress-header.tsx +113 -0
  284. package/src/theme/components/nav/ciderpress-layout-context.tsx +49 -0
  285. package/src/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
  286. package/src/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
  287. package/src/theme/components/nav/ciderpress-nav-menu.css +130 -0
  288. package/src/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
  289. package/src/theme/components/nav/ciderpress-nav-search.css +73 -0
  290. package/src/theme/components/nav/ciderpress-nav-search.tsx +55 -0
  291. package/src/theme/components/nav/ciderpress-nav-social-links.css +35 -0
  292. package/src/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
  293. package/src/theme/components/nav/floating-branch-indicator.css +106 -0
  294. package/src/theme/components/nav/floating-branch-indicator.tsx +109 -0
  295. package/src/theme/components/nav/layout.tsx +268 -0
  296. package/src/theme/components/nav/mobile-nav-cta.tsx +79 -0
  297. package/src/theme/components/nav/nav-divider.css +15 -0
  298. package/src/theme/components/nav/nav-divider.tsx +19 -0
  299. package/src/theme/components/nav/nav-logo.css +42 -0
  300. package/src/theme/components/nav/nav-logo.tsx +262 -0
  301. package/src/theme/components/nav/theme-switcher.css +92 -0
  302. package/src/theme/components/nav/theme-switcher.tsx +298 -0
  303. package/src/theme/components/nav/topbar-cta.css +45 -0
  304. package/src/theme/components/nav/topbar-cta.tsx +39 -0
  305. package/src/theme/components/nav/variant-toggle.css +70 -0
  306. package/src/theme/components/nav/variant-toggle.tsx +83 -0
  307. package/src/theme/components/nav/version-chip.css +31 -0
  308. package/src/theme/components/nav/version-chip.tsx +45 -0
  309. package/src/theme/components/nav/vscode-tag.css +32 -0
  310. package/src/theme/components/nav/vscode-tag.tsx +20 -0
  311. package/src/theme/components/openapi/code-sample.tsx +341 -0
  312. package/src/theme/components/openapi/copy-markdown-button.tsx +41 -0
  313. package/src/theme/components/openapi/icons.tsx +45 -0
  314. package/src/theme/components/openapi/index.ts +6 -0
  315. package/src/theme/components/openapi/method-badge.tsx +24 -0
  316. package/src/theme/components/openapi/openapi.css +665 -0
  317. package/src/theme/components/openapi/operation.tsx +200 -0
  318. package/src/theme/components/openapi/overview.tsx +207 -0
  319. package/src/theme/components/openapi/parameters-table.tsx +149 -0
  320. package/src/theme/components/openapi/request-body.tsx +90 -0
  321. package/src/theme/components/openapi/response-list.tsx +112 -0
  322. package/src/theme/components/openapi/schema-viewer.tsx +277 -0
  323. package/src/theme/components/openapi/security-badges.tsx +63 -0
  324. package/src/theme/components/openapi/spec-utils.ts +122 -0
  325. package/src/theme/components/shared/accordion.css +118 -0
  326. package/src/theme/components/shared/accordion.stories.tsx +96 -0
  327. package/src/theme/components/shared/accordion.tsx +191 -0
  328. package/src/theme/components/shared/brand-logo.stories.tsx +49 -0
  329. package/src/theme/components/shared/brand-mark.stories.tsx +53 -0
  330. package/src/theme/components/shared/browser-window.css +1 -0
  331. package/src/theme/components/shared/browser-window.stories.tsx +100 -0
  332. package/src/theme/components/shared/browser-window.tsx +2 -0
  333. package/src/theme/components/shared/card.stories.tsx +50 -0
  334. package/src/theme/components/shared/card.tsx +35 -0
  335. package/src/theme/components/shared/ciderpress-logo.tsx +93 -0
  336. package/src/theme/components/shared/ciderpress-mark.tsx +77 -0
  337. package/src/theme/components/shared/color.css +56 -0
  338. package/src/theme/components/shared/color.stories.tsx +47 -0
  339. package/src/theme/components/shared/color.tsx +69 -0
  340. package/src/theme/components/shared/columns.css +37 -0
  341. package/src/theme/components/shared/columns.stories.tsx +91 -0
  342. package/src/theme/components/shared/columns.tsx +50 -0
  343. package/src/theme/components/shared/desktop-window.css +339 -0
  344. package/src/theme/components/shared/desktop-window.tsx +535 -0
  345. package/src/theme/components/shared/field.css +158 -0
  346. package/src/theme/components/shared/field.stories.tsx +100 -0
  347. package/src/theme/components/shared/field.tsx +186 -0
  348. package/src/theme/components/shared/frame.css +39 -0
  349. package/src/theme/components/shared/frame.stories.tsx +49 -0
  350. package/src/theme/components/shared/frame.tsx +76 -0
  351. package/src/theme/components/shared/icon.stories.tsx +90 -0
  352. package/src/theme/components/shared/icon.tsx +41 -0
  353. package/src/theme/components/shared/prompt.css +178 -0
  354. package/src/theme/components/shared/prompt.stories.tsx +57 -0
  355. package/src/theme/components/shared/prompt.tsx +369 -0
  356. package/src/theme/components/shared/resolve-card-icon.ts +28 -0
  357. package/src/theme/components/shared/section-card.stories.tsx +51 -0
  358. package/src/theme/components/shared/section-card.tsx +44 -0
  359. package/src/theme/components/shared/section-grid.stories.tsx +46 -0
  360. package/src/theme/components/shared/section-grid.tsx +15 -0
  361. package/src/theme/components/shared/status-badge.css +37 -0
  362. package/src/theme/components/shared/status-badge.stories.tsx +61 -0
  363. package/src/theme/components/shared/status-badge.tsx +74 -0
  364. package/src/theme/components/shared/steps.css +88 -0
  365. package/src/theme/components/shared/steps.stories.tsx +68 -0
  366. package/src/theme/components/shared/steps.tsx +100 -0
  367. package/src/theme/components/shared/tech-icon-table.stories.tsx +29 -0
  368. package/src/theme/components/shared/tech-icon-table.tsx +71 -0
  369. package/src/theme/components/shared/tech-tag.stories.tsx +40 -0
  370. package/src/theme/components/shared/tech-tag.tsx +31 -0
  371. package/src/theme/components/shared/theme-color-palette.css +80 -0
  372. package/src/theme/components/shared/theme-color-palette.stories.tsx +52 -0
  373. package/src/theme/components/shared/theme-color-palette.tsx +275 -0
  374. package/src/theme/components/shared/tooltip.css +69 -0
  375. package/src/theme/components/shared/tooltip.stories.tsx +72 -0
  376. package/src/theme/components/shared/tooltip.tsx +77 -0
  377. package/src/theme/components/sidebar/framework-picker.css +77 -0
  378. package/src/theme/components/sidebar/framework-picker.tsx +78 -0
  379. package/src/theme/components/sidebar/sidebar-filter.test.ts +140 -0
  380. package/src/theme/components/sidebar/sidebar-filter.ts +79 -0
  381. package/src/theme/components/sidebar/sidebar-links.css +102 -0
  382. package/src/theme/components/sidebar/sidebar-links.tsx +122 -0
  383. package/src/theme/components/sidebar/sidebar-promo.css +42 -0
  384. package/src/theme/components/sidebar/sidebar-promo.tsx +52 -0
  385. package/src/theme/components/sidebar/sidebar-scope.tsx +151 -0
  386. package/src/theme/components/sidebar/sidebar-toggle.css +181 -0
  387. package/src/theme/components/sidebar/sidebar-toggle.tsx +127 -0
  388. package/src/theme/components/theme-provider.tsx +637 -0
  389. package/src/theme/components/workspaces/card.css +151 -0
  390. package/src/theme/components/workspaces/card.tsx +166 -0
  391. package/src/theme/components/workspaces/grid.tsx +62 -0
  392. package/src/theme/css.d.ts +1 -0
  393. package/src/theme/env.d.ts +12 -0
  394. package/src/theme/fonts/GeistMono-Variable.woff2 +0 -0
  395. package/src/theme/fonts/GeistPixel-Square.woff2 +0 -0
  396. package/src/theme/fonts/GeistSans-Variable.woff2 +0 -0
  397. package/src/theme/hooks/use-ciderpress.ts +61 -0
  398. package/src/theme/hooks/use-nav-items.ts +76 -0
  399. package/src/theme/icons/index.ts +2 -0
  400. package/src/theme/icons/tech-map.ts +228 -0
  401. package/src/theme/index.tsx +180 -0
  402. package/src/theme/lib/read-social-links.ts +27 -0
  403. package/src/theme/lib/route-link.tsx +126 -0
  404. package/src/theme/lib/safe-url.test.ts +0 -0
  405. package/src/theme/lib/safe-url.ts +68 -0
  406. package/src/theme/lib/theme-favicon.ts +125 -0
  407. package/src/theme/lib/user-config-stub.ts +12 -0
  408. package/src/theme/styles/layers.css +32 -0
  409. package/src/theme/styles/overrides/badge.css +26 -0
  410. package/src/theme/styles/overrides/content-footer.css +80 -0
  411. package/src/theme/styles/overrides/details.css +61 -0
  412. package/src/theme/styles/overrides/fonts.css +32 -0
  413. package/src/theme/styles/overrides/home-card.css +133 -0
  414. package/src/theme/styles/overrides/home.css +243 -0
  415. package/src/theme/styles/overrides/rail.css +337 -0
  416. package/src/theme/styles/overrides/rspress.css +62 -0
  417. package/src/theme/styles/overrides/scrollbar.css +25 -0
  418. package/src/theme/styles/overrides/section-card.css +114 -0
  419. package/src/theme/styles/overrides/sidebar.css +144 -0
  420. package/src/theme/styles/overrides/tokens.css +288 -0
  421. package/src/theme/styles/overrides/vscode.css +88 -0
  422. package/src/theme/styles/themes/amber.css +545 -0
  423. package/src/theme/styles/themes/arcade-fx.css +366 -0
  424. package/src/theme/styles/themes/arcade.css +273 -0
  425. package/src/theme/styles/themes/grannysmith.css +545 -0
  426. package/src/theme/styles/themes/honeycrisp.css +545 -0
  427. package/src/theme/styles/themes/midnight.css +273 -0
  428. package/src/theme/styles/themes/mulled.css +817 -0
@@ -0,0 +1,39 @@
1
+ import type React from 'react'
2
+
3
+ import { RouteLink } from '../../lib/route-link.tsx'
4
+ import { safeUrl } from '../../lib/safe-url.ts'
5
+
6
+ import './topbar-cta.css'
7
+
8
+ export interface TopbarCTAProps {
9
+ /**
10
+ * Button label.
11
+ */
12
+ readonly text: string
13
+ /**
14
+ * Destination URL.
15
+ */
16
+ readonly href: string
17
+ }
18
+
19
+ /**
20
+ * TopbarCTA — mint primary pill rendered at the right end of the topbar
21
+ * to drive the headline conversion (e.g. "Get started →").
22
+ *
23
+ * Renders `null` when `href` fails `safeUrl()` validation — config-driven
24
+ * hrefs must not become script-execution sinks.
25
+ *
26
+ * @param props - Button configuration.
27
+ * @returns React element, or `null` when the href fails URL validation.
28
+ */
29
+ export function TopbarCTA(props: TopbarCTAProps): React.ReactElement | null {
30
+ const href = safeUrl(props.href)
31
+ if (href === null) {
32
+ return null
33
+ }
34
+ return (
35
+ <RouteLink className="cp-topbar-cta" href={href}>
36
+ {props.text}
37
+ </RouteLink>
38
+ )
39
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * VariantToggle — sun/moon button that flips the active theme's variant.
3
+ *
4
+ * Both icons render into the DOM; CSS hides whichever doesn't match the
5
+ * current `html[data-cp-variant]` value. When dark, the sun is visible
6
+ * (click to go light); when light, the moon is visible (click to go
7
+ * dark) — the icon telegraphs the destination, matching the convention
8
+ * used by GitHub, Vercel, and most modern docs sites.
9
+ *
10
+ * Theme-author API:
11
+ * --cp-variant-toggle-size button width/height (default 32px)
12
+ * --cp-variant-toggle-radius border-radius (defaults to --rp-radius)
13
+ */
14
+ .cp-variant-toggle {
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ width: var(--cp-variant-toggle-size, 32px);
19
+ height: var(--cp-variant-toggle-size, 32px);
20
+ padding: 0;
21
+ border: 1px solid var(--cp-c-border);
22
+ border-radius: var(--cp-variant-toggle-radius, var(--rp-radius));
23
+ background: var(--cp-c-bg);
24
+ color: var(--cp-c-text-2);
25
+ cursor: pointer;
26
+ transition:
27
+ color 0.2s,
28
+ border-color 0.2s;
29
+ }
30
+
31
+ .cp-variant-toggle:hover {
32
+ color: var(--cp-c-text-1);
33
+ border-color: var(--cp-c-brand-1);
34
+ }
35
+
36
+ /* ── Icon swap ─────────────────────────────────────────────────────
37
+ * Visibility is driven entirely by the `[data-cp-variant]` attribute
38
+ * set on `<html>` (by the head IIFE for first paint, then by the
39
+ * toggle's click handler).
40
+ * ──────────────────────────────────────────────────────────────── */
41
+ .cp-variant-toggle__icon {
42
+ display: none;
43
+ align-items: center;
44
+ justify-content: center;
45
+ line-height: 0;
46
+ }
47
+
48
+ html[data-cp-variant='dark'] .cp-variant-toggle__icon--sun {
49
+ display: inline-flex;
50
+ }
51
+
52
+ html[data-cp-variant='light'] .cp-variant-toggle__icon--moon {
53
+ display: inline-flex;
54
+ }
55
+
56
+ /* SSR / pre-hydration fallback — before the head IIFE has set
57
+ `data-cp-variant`, neither selector above matches. Show the moon so
58
+ the button isn't empty during the first paint window. */
59
+ html:not([data-cp-variant]) .cp-variant-toggle__icon--moon {
60
+ display: inline-flex;
61
+ }
62
+
63
+ /* ── Single-variant themes — hide the toggle when the active theme
64
+ only ships one variant. Mirrors the existing rule that hides
65
+ Rspress's `.rp-switch-appearance` for the same reason (see
66
+ `styles/overrides/rspress.css`). ────────────────────────────── */
67
+ html[data-cp-variants='dark'] .cp-variant-toggle,
68
+ html[data-cp-variants='light'] .cp-variant-toggle {
69
+ display: none;
70
+ }
@@ -0,0 +1,83 @@
1
+ import { match } from 'massaman/match'
2
+ import { useCallback } from 'react'
3
+ import type React from 'react'
4
+
5
+ import { Icon } from '../shared/icon.tsx'
6
+
7
+ import './variant-toggle.css'
8
+
9
+ type Variant = 'dark' | 'light'
10
+
11
+ /**
12
+ * VariantToggle — single button that flips between the active theme's
13
+ * dark and light variants. Both icons (sun + moon) live in the DOM and
14
+ * are toggled purely via CSS against `html[data-cp-variant]`, so the
15
+ * button carries no React state and survives SSR with no hydration
16
+ * mismatch.
17
+ *
18
+ * Hidden via `variant-toggle.css` when the active theme only declares
19
+ * one variant — mirrors the existing `[data-cp-variants]` rule that
20
+ * already hides Rspress's `.rp-switch-appearance`.
21
+ *
22
+ * Click handler mirrors the same DOM + `localStorage` writes the head
23
+ * IIFE and `<ThemeProvider />` perform — keep all three in sync.
24
+ *
25
+ * @returns Toggle button element
26
+ */
27
+ export function VariantToggle(): React.ReactElement {
28
+ const handleClick = useCallback(() => {
29
+ const html = document.documentElement
30
+ const next = match(html.dataset.cpVariant)
31
+ .with('light', () => 'dark' as const)
32
+ .otherwise(() => 'light' as const)
33
+ applyVariant({ html, variant: next })
34
+ }, [])
35
+
36
+ return (
37
+ <button
38
+ type="button"
39
+ className="cp-variant-toggle"
40
+ onClick={handleClick}
41
+ aria-label="Toggle light and dark mode"
42
+ title="Toggle light and dark mode"
43
+ >
44
+ <span className="cp-variant-toggle__icon cp-variant-toggle__icon--sun">
45
+ <Icon icon="mdi:weather-sunny" width={16} height={16} />
46
+ </span>
47
+ <span className="cp-variant-toggle__icon cp-variant-toggle__icon--moon">
48
+ <Icon icon="mdi:weather-night" width={16} height={16} />
49
+ </span>
50
+ </button>
51
+ )
52
+ }
53
+
54
+ export { VariantToggle as default }
55
+
56
+ /**
57
+ * Apply the new variant to the DOM and persist it. Mirrors the writes
58
+ * performed by `buildHeadScriptBody` (head IIFE in
59
+ * `packages/ui/src/config.ts`) and `<ThemeProvider />`'s `applyVariant`
60
+ * so the three sources of truth never diverge.
61
+ *
62
+ * @private
63
+ * @param params - HTML element and target variant
64
+ */
65
+ function applyVariant(params: { readonly html: HTMLElement; readonly variant: Variant }): void {
66
+ const { html, variant } = params
67
+ html.dataset.cpVariant = variant
68
+ match(variant)
69
+ .with('dark', () => {
70
+ html.classList.add('rp-dark', 'dark')
71
+ html.dataset.dark = 'true'
72
+ })
73
+ .otherwise(() => {
74
+ html.classList.remove('rp-dark', 'dark')
75
+ html.dataset.dark = 'false'
76
+ })
77
+ try {
78
+ localStorage.setItem('rspress-theme-appearance', variant)
79
+ localStorage.setItem('ciderpress-variant', variant)
80
+ } catch {
81
+ // storage unavailable (privacy mode, quota) — DOM is still correct
82
+ }
83
+ }
@@ -0,0 +1,31 @@
1
+ /* Make the Rspress brand title row flex so the portalled VersionChip
2
+ sits inline with the logo/text instead of stacking below it. */
3
+ html .rp-nav__title {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ gap: 0;
7
+ }
8
+
9
+ .cp-version-chip {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ gap: 10px;
13
+ white-space: nowrap;
14
+ margin-left: 10px;
15
+ height: 22px;
16
+ line-height: 1;
17
+ }
18
+
19
+ .cp-version-chip__divider {
20
+ display: inline-block;
21
+ width: 1px;
22
+ height: 16px;
23
+ background: var(--cp-c-border);
24
+ }
25
+
26
+ .cp-version-chip__text {
27
+ font-family: var(--cp-font-family-mono);
28
+ font-size: 11px;
29
+ font-weight: 400;
30
+ color: var(--cp-c-text-3);
31
+ }
@@ -0,0 +1,45 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { createPortal } from 'react-dom'
3
+
4
+ import './version-chip.css'
5
+
6
+ export interface VersionChipProps {
7
+ /**
8
+ * Version label, e.g. "v0.5".
9
+ */
10
+ readonly version: string
11
+ }
12
+
13
+ /**
14
+ * VersionChip — small mono label rendered next to the topbar brand to
15
+ * advertise the active package version. Renders a thin vertical divider
16
+ * before the version text so it visually attaches to the brand:
17
+ * `ciderpress | v0.5`.
18
+ *
19
+ * Portals into `.rp-nav__title` so the chip sits directly beside the
20
+ * Rspress logo/title rather than in the nav-menu area. Falls back to
21
+ * inline rendering when the title node is not yet mounted.
22
+ *
23
+ * @param props - Version chip configuration.
24
+ * @returns React element.
25
+ */
26
+ export function VersionChip(props: VersionChipProps): React.ReactElement | null {
27
+ const [target, setTarget] = useState<HTMLElement | null>(null)
28
+
29
+ useEffect(() => {
30
+ const el = globalThis.document.querySelector('.rp-nav__title') as HTMLElement | null
31
+ setTarget(el)
32
+ }, [])
33
+
34
+ const chip = (
35
+ <span className="cp-version-chip">
36
+ <span className="cp-version-chip__divider" aria-hidden="true" />
37
+ <span className="cp-version-chip__text">{props.version}</span>
38
+ </span>
39
+ )
40
+
41
+ if (target === null) {
42
+ return null
43
+ }
44
+ return createPortal(chip, target)
45
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * VS Code tag pill — mode indicator badge positioned in the nav bar.
3
+ */
4
+
5
+ .cp-vscode-tag {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ gap: 5px;
9
+ margin-left: 6px;
10
+ padding: 3px 10px;
11
+ border-radius: 20px;
12
+ background: var(--cp-c-bg-soft);
13
+ border: 1px solid var(--cp-c-brand-1, #60a5fa);
14
+ color: var(--cp-c-brand-1, #60a5fa);
15
+ font-family: var(--cp-font-family-mono);
16
+ font-size: 11px;
17
+ font-weight: 600;
18
+ line-height: 1;
19
+ white-space: nowrap;
20
+ }
21
+
22
+ .cp-vscode-tag svg {
23
+ width: 14px;
24
+ height: 14px;
25
+ flex-shrink: 0;
26
+ }
27
+
28
+ @media (max-width: 768px) {
29
+ .cp-vscode-tag__text {
30
+ display: none;
31
+ }
32
+ }
@@ -0,0 +1,20 @@
1
+ import type React from 'react'
2
+
3
+ import './vscode-tag.css'
4
+ import { Icon } from '../shared/icon.tsx'
5
+
6
+ /**
7
+ * VS Code mode indicator — pill-shaped badge rendered next to the
8
+ * BranchTag when the page is loaded inside the VS Code webview
9
+ * (detected via `?env=vscode` query parameter).
10
+ *
11
+ * @returns React element with the VS Code badge
12
+ */
13
+ export function VscodeTag(): React.ReactElement {
14
+ return (
15
+ <span className="cp-vscode-tag" title="VS Code preview mode" aria-label="VS Code preview mode">
16
+ <Icon icon="vscode-icons:file-type-vscode" width={14} height={14} />
17
+ <span className="cp-vscode-tag__text">vscode</span>
18
+ </span>
19
+ )
20
+ }
@@ -0,0 +1,341 @@
1
+ import { CodeBlockRuntime } from '@rspress/core/theme'
2
+ import { match, P } from 'massaman/match'
3
+ import type React from 'react'
4
+ import { useState } from 'react'
5
+
6
+ import { extractBodyExample, isBodyMethod } from './spec-utils'
7
+
8
+ export interface CodeSampleProps {
9
+ /**
10
+ * HTTP method (get, post, etc.).
11
+ */
12
+ readonly method: string
13
+ /**
14
+ * URL path (e.g. /users/{id}).
15
+ */
16
+ readonly path: string
17
+ /**
18
+ * Base URL for the API server.
19
+ */
20
+ readonly baseUrl: string
21
+ /**
22
+ * Operation parameters for generating sample values.
23
+ */
24
+ readonly parameters?: readonly Record<string, unknown>[]
25
+ /**
26
+ * Request body for POST/PUT/PATCH examples.
27
+ */
28
+ readonly requestBody?: Record<string, unknown>
29
+ }
30
+
31
+ interface TabConfig {
32
+ readonly label: string
33
+ readonly lang: string
34
+ readonly generator: (props: CodeSampleProps) => string
35
+ }
36
+
37
+ const TABS: readonly TabConfig[] = [
38
+ { label: 'cURL', lang: 'bash', generator: generateCurl },
39
+ { label: 'JavaScript', lang: 'javascript', generator: generateJavascript },
40
+ { label: 'Python', lang: 'python', generator: generatePython },
41
+ { label: 'Go', lang: 'go', generator: generateGo },
42
+ { label: 'Ruby', lang: 'ruby', generator: generateRuby },
43
+ { label: 'Java', lang: 'java', generator: generateJava },
44
+ ]
45
+
46
+ /**
47
+ * Auto-generated code examples for an API operation.
48
+ *
49
+ * Renders cURL, JavaScript, Python, Go, Ruby, and Java code
50
+ * using Rspress's CodeBlockRuntime for full syntax highlighting.
51
+ *
52
+ * @param props - Code sample props including method, path, baseUrl, and optional body
53
+ * @returns React element with tabbed code examples
54
+ */
55
+ export function CodeSample(props: CodeSampleProps): React.ReactElement {
56
+ const [activeTab, setActiveTab] = useState<string>('cURL')
57
+
58
+ const activeConfig = TABS.find((tab) => tab.label === activeTab)
59
+ const resolved = match(activeConfig)
60
+ .with(P.nonNullable, (config) => ({
61
+ code: config.generator(props),
62
+ lang: config.lang,
63
+ }))
64
+ .otherwise(() => ({ code: generateCurl(props), lang: 'bash' }))
65
+
66
+ return (
67
+ <div className="cp-oas-code-sample">
68
+ <div className="cp-oas-code-sample__title">Code Examples</div>
69
+ <div className="cp-oas-code-sample__tabs">
70
+ {TABS.map((tab) => (
71
+ <button
72
+ key={tab.label}
73
+ type="button"
74
+ className={match(activeTab === tab.label)
75
+ .with(true, () => 'cp-oas-code-sample__tab cp-oas-code-sample__tab--active')
76
+ .otherwise(() => 'cp-oas-code-sample__tab')}
77
+ onClick={() => {
78
+ setActiveTab(tab.label)
79
+ }}
80
+ >
81
+ {tab.label}
82
+ </button>
83
+ ))}
84
+ </div>
85
+ <div className="cp-oas-code-sample__block">
86
+ <CodeBlockRuntime lang={resolved.lang} code={resolved.code} />
87
+ </div>
88
+ </div>
89
+ )
90
+ }
91
+
92
+ /**
93
+ * Build a full URL from base URL and path.
94
+ *
95
+ * @private
96
+ * @param input - Object with baseUrl and path
97
+ * @returns Full URL string
98
+ */
99
+ function buildUrl(input: { readonly baseUrl: string; readonly path: string }): string {
100
+ const base = input.baseUrl.replace(/\/+$/, '')
101
+ if (input.path.startsWith('/')) {
102
+ return `${base}${input.path}`
103
+ }
104
+ return `${base}/${input.path}`
105
+ }
106
+
107
+ /**
108
+ * Generate a cURL code example for the operation.
109
+ *
110
+ * @private
111
+ * @param props - Code sample props
112
+ * @returns cURL command string
113
+ */
114
+ function generateCurl(props: CodeSampleProps): string {
115
+ const url = buildUrl({ baseUrl: props.baseUrl, path: props.path })
116
+ const method = props.method.toUpperCase()
117
+ const headers = match(isBodyMethod(props.method.toLowerCase()))
118
+ .with(true, () => " \\\n -H 'Content-Type: application/json'")
119
+ .otherwise(() => '')
120
+ const body = match(extractBodyExample(props.requestBody))
121
+ .with(P.nonNullable, (ex) => ` \\\n -d '${JSON.stringify(ex)}'`)
122
+ .otherwise(() => '')
123
+ return `curl -X ${method} '${url}'${headers}${body}`
124
+ }
125
+
126
+ /**
127
+ * Generate a Python requests code example for the operation.
128
+ *
129
+ * @private
130
+ * @param props - Code sample props
131
+ * @returns Python code string
132
+ */
133
+ function generatePython(props: CodeSampleProps): string {
134
+ const url = buildUrl({ baseUrl: props.baseUrl, path: props.path })
135
+ const method = props.method.toLowerCase()
136
+ const bodyExample = extractBodyExample(props.requestBody)
137
+ const hasBody = isBodyMethod(method) && bodyExample !== null
138
+
139
+ const payloadLines = match(hasBody)
140
+ .with(true, () => [`payload = ${JSON.stringify(bodyExample, null, 4)}`, ''])
141
+ .otherwise(() => [])
142
+
143
+ const jsonArg = match(hasBody)
144
+ .with(true, () => ',\n json=payload')
145
+ .otherwise(() => '')
146
+
147
+ return [
148
+ 'import requests',
149
+ '',
150
+ ...payloadLines,
151
+ `response = requests.${method}(`,
152
+ ` "${url}"${jsonArg}`,
153
+ ')',
154
+ '',
155
+ 'print(response.json())',
156
+ ].join('\n')
157
+ }
158
+
159
+ /**
160
+ * Generate a JavaScript fetch code example for the operation.
161
+ *
162
+ * @private
163
+ * @param props - Code sample props
164
+ * @returns JavaScript code string
165
+ */
166
+ function generateJavascript(props: CodeSampleProps): string {
167
+ const url = buildUrl({ baseUrl: props.baseUrl, path: props.path })
168
+ const method = props.method.toUpperCase()
169
+ const hasBody = isBodyMethod(props.method.toLowerCase())
170
+ const bodyExample = extractBodyExample(props.requestBody)
171
+
172
+ const headersStr = match(hasBody)
173
+ .with(true, () => "\n headers: { 'Content-Type': 'application/json' },")
174
+ .otherwise(() => '')
175
+
176
+ const bodyStr = match(hasBody && bodyExample !== null)
177
+ .with(true, () => `\n body: JSON.stringify(${JSON.stringify(bodyExample, null, 2)}),`)
178
+ .otherwise(() => '')
179
+
180
+ return [
181
+ `const response = await fetch('${url}', {`,
182
+ ` method: '${method}',${headersStr}${bodyStr}`,
183
+ '})',
184
+ '',
185
+ 'const data = await response.json()',
186
+ 'console.log(data)',
187
+ ].join('\n')
188
+ }
189
+
190
+ /**
191
+ * Generate a Go net/http code example for the operation.
192
+ *
193
+ * @private
194
+ * @param props - Code sample props
195
+ * @returns Go code string
196
+ */
197
+ function generateGo(props: CodeSampleProps): string {
198
+ const url = buildUrl({ baseUrl: props.baseUrl, path: props.path })
199
+ const method = props.method.toUpperCase()
200
+ const hasBody = isBodyMethod(props.method.toLowerCase())
201
+ const bodyExample = extractBodyExample(props.requestBody)
202
+
203
+ const hasBodyPayload = hasBody && bodyExample !== null
204
+ const escapedBody = match(hasBodyPayload)
205
+ .with(true, () => JSON.stringify(bodyExample).replaceAll('"', String.raw`\"`))
206
+ .otherwise(() => '')
207
+
208
+ const bodySetup = match(hasBodyPayload)
209
+ .with(true, () =>
210
+ [
211
+ `\tpayload := strings.NewReader("${escapedBody}")`,
212
+ `\treq, err := http.NewRequest("${method}", "${url}", payload)`,
213
+ ].join('\n')
214
+ )
215
+ .otherwise(() => `\treq, err := http.NewRequest("${method}", "${url}", nil)`)
216
+
217
+ const contentTypeHeader = match(hasBody)
218
+ .with(true, () => '\treq.Header.Set("Content-Type", "application/json")')
219
+ .otherwise(() => '')
220
+
221
+ const stringsImport = match(hasBodyPayload)
222
+ .with(true, () => ['\t"strings"'])
223
+ .otherwise(() => [])
224
+
225
+ return [
226
+ 'package main',
227
+ '',
228
+ 'import (',
229
+ '\t"fmt"',
230
+ '\t"io"',
231
+ '\t"net/http"',
232
+ ...stringsImport,
233
+ ')',
234
+ '',
235
+ 'func main() {',
236
+ bodySetup,
237
+ '\tif err != nil {',
238
+ '\t\tpanic(err)',
239
+ '\t}',
240
+ contentTypeHeader,
241
+ '',
242
+ '\tresp, err := http.DefaultClient.Do(req)',
243
+ '\tif err != nil {',
244
+ '\t\tpanic(err)',
245
+ '\t}',
246
+ '\tdefer resp.Body.Close()',
247
+ '',
248
+ '\tbody, _ := io.ReadAll(resp.Body)',
249
+ '\tfmt.Println(string(body))',
250
+ '}',
251
+ ].join('\n')
252
+ }
253
+
254
+ /**
255
+ * Generate a Ruby net/http code example for the operation.
256
+ *
257
+ * @private
258
+ * @param props - Code sample props
259
+ * @returns Ruby code string
260
+ */
261
+ function generateRuby(props: CodeSampleProps): string {
262
+ const url = buildUrl({ baseUrl: props.baseUrl, path: props.path })
263
+ const method = props.method.toLowerCase()
264
+ const hasBody = isBodyMethod(method)
265
+ const bodyExample = extractBodyExample(props.requestBody)
266
+
267
+ const uriLines = ["require 'net/http'", "require 'json'", '', `uri = URI('${url}')`]
268
+
269
+ const methodClass = match(method)
270
+ .with('get', () => 'Get')
271
+ .with('post', () => 'Post')
272
+ .with('put', () => 'Put')
273
+ .with('patch', () => 'Patch')
274
+ .with('delete', () => 'Delete')
275
+ .otherwise(() => 'Get')
276
+
277
+ const requestLines = [`request = Net::HTTP::${methodClass}.new(uri)`]
278
+
279
+ const bodyLines = match(hasBody && bodyExample !== null)
280
+ .with(true, () => [
281
+ "request['Content-Type'] = 'application/json'",
282
+ `request.body = '${JSON.stringify(bodyExample)}'`,
283
+ ])
284
+ .otherwise(() => [])
285
+
286
+ return [
287
+ ...uriLines,
288
+ ...requestLines,
289
+ ...bodyLines,
290
+ '',
291
+ `response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: ${String(props.baseUrl.startsWith('https'))}) do |http|`,
292
+ ' http.request(request)',
293
+ 'end',
294
+ '',
295
+ 'puts JSON.parse(response.body)',
296
+ ].join('\n')
297
+ }
298
+
299
+ /**
300
+ * Generate a Java HttpClient code example for the operation.
301
+ *
302
+ * @private
303
+ * @param props - Code sample props
304
+ * @returns Java code string
305
+ */
306
+ function generateJava(props: CodeSampleProps): string {
307
+ const url = buildUrl({ baseUrl: props.baseUrl, path: props.path })
308
+ const method = props.method.toUpperCase()
309
+ const hasBody = isBodyMethod(props.method.toLowerCase())
310
+ const bodyExample = extractBodyExample(props.requestBody)
311
+
312
+ const builderMethod = match(hasBody && bodyExample !== null)
313
+ .with(
314
+ true,
315
+ () =>
316
+ ` .method("${method}", HttpRequest.BodyPublishers.ofString("${JSON.stringify(bodyExample).replaceAll('"', String.raw`\"`)}"))`
317
+ )
318
+ .otherwise(() => ` .method("${method}", HttpRequest.BodyPublishers.noBody())`)
319
+
320
+ const contentTypeHeader = match(hasBody)
321
+ .with(true, () => '\n .header("Content-Type", "application/json")')
322
+ .otherwise(() => '')
323
+
324
+ return [
325
+ 'import java.net.http.*;',
326
+ 'import java.net.URI;',
327
+ '',
328
+ 'HttpClient client = HttpClient.newHttpClient();',
329
+ '',
330
+ 'HttpRequest request = HttpRequest.newBuilder()',
331
+ ` .uri(URI.create("${url}"))`,
332
+ `${builderMethod}${contentTypeHeader}`,
333
+ ' .build();',
334
+ '',
335
+ 'HttpResponse<String> response = client.send(',
336
+ ' request, HttpResponse.BodyHandlers.ofString()',
337
+ ');',
338
+ '',
339
+ 'System.out.println(response.body());',
340
+ ].join('\n')
341
+ }