@speakeasy-api/moonshine 2.0.0-alpha.1 → 2.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -23
  3. package/package.json +33 -50
  4. package/scripts/generate-utility-docs.js +324 -0
  5. package/src/assets/icons/external/github.svg +3 -0
  6. package/src/assets/icons/external/maven.svg +152 -0
  7. package/src/assets/icons/external/npm.svg +4 -0
  8. package/src/assets/icons/external/nuget.svg +5 -0
  9. package/src/assets/icons/external/packagist.svg +1 -0
  10. package/src/assets/icons/external/pypi.svg +182 -0
  11. package/src/assets/icons/external/rubygems.svg +14 -0
  12. package/src/assets/icons/external/terraform.svg +1 -0
  13. package/src/assets/icons/languages/csharp.svg +1 -0
  14. package/src/assets/icons/languages/go.svg +1 -0
  15. package/src/assets/icons/languages/java.svg +1 -0
  16. package/src/assets/icons/languages/json.svg +2 -0
  17. package/src/assets/icons/languages/php.svg +1 -0
  18. package/src/assets/icons/languages/postman.svg +3 -0
  19. package/src/assets/icons/languages/python.svg +1 -0
  20. package/src/assets/icons/languages/ruby.svg +1 -0
  21. package/src/assets/icons/languages/swift.svg +1 -0
  22. package/src/assets/icons/languages/terraform.svg +1 -0
  23. package/src/assets/icons/languages/typescript.svg +1 -0
  24. package/src/assets/icons/languages/unity.svg +1 -0
  25. package/src/base.css +12 -12
  26. package/src/components/AIChat/AIChatContainer.tsx +71 -0
  27. package/src/components/AIChat/AIChatMessage.tsx +135 -0
  28. package/src/components/AIChat/AIChatMessageComposer.tsx +175 -0
  29. package/src/components/AIChat/AIChatMessageList.tsx +34 -0
  30. package/src/components/AIChat/AIChatModelSelector.tsx +159 -0
  31. package/src/components/AIChat/componentsTypes.ts +36 -0
  32. package/src/components/AIChat/context.ts +15 -0
  33. package/src/components/AIChat/index.ts +12 -0
  34. package/src/components/AIChat/parts/AIChatMessageFilePart.tsx +129 -0
  35. package/src/components/AIChat/parts/AIChatMessageReasoningPart.tsx +23 -0
  36. package/src/components/AIChat/parts/AIChatMessageSourcePart.tsx +58 -0
  37. package/src/components/AIChat/parts/AIChatMessageTextPart.tsx +33 -0
  38. package/src/components/AIChat/parts/AIChatMessageToolInvocationPart.tsx +53 -0
  39. package/src/components/AIChat/parts/AIChatMessageToolPart.tsx +395 -0
  40. package/src/components/AIChat/parts/AIChatMessageToolResultPart.tsx +46 -0
  41. package/src/components/AIChat/toolCallApproval.ts +61 -0
  42. package/src/components/AIChat/types.ts +97 -0
  43. package/src/components/ActionBar/index.tsx +184 -0
  44. package/src/components/Alert/index.tsx +118 -0
  45. package/src/components/Alert/types.ts +12 -0
  46. package/src/components/AppLayout/context.tsx +31 -0
  47. package/src/components/AppLayout/index.tsx +550 -0
  48. package/src/components/AppLayout/provider.tsx +40 -0
  49. package/src/components/AppLayout/useAppLayoutKeys.ts +26 -0
  50. package/src/components/Badge/index.tsx +227 -0
  51. package/src/components/Button/index.tsx +531 -0
  52. package/src/components/Card/index.tsx +193 -0
  53. package/src/components/CodeEditorLayout/index.tsx +394 -0
  54. package/src/components/CodeEditorLayout/styles.module.css +8 -0
  55. package/src/components/CodeHighlight/Pre.tsx +63 -0
  56. package/src/components/CodePlayground/index.tsx +411 -0
  57. package/src/components/CodeSnippet/codeSnippet.css +97 -0
  58. package/src/components/CodeSnippet/index.tsx +224 -0
  59. package/src/components/Combobox/index.tsx +193 -0
  60. package/src/components/Command/index.tsx +152 -0
  61. package/src/components/Container/index.tsx +31 -0
  62. package/src/components/ContextDropdown/index.tsx +150 -0
  63. package/src/components/Dialog/index.tsx +123 -0
  64. package/src/components/DragNDrop/DragNDropArea.tsx +30 -0
  65. package/src/components/DragNDrop/DragOverlay.tsx +4 -0
  66. package/src/components/DragNDrop/Draggable.tsx +97 -0
  67. package/src/components/DragNDrop/Droppable.tsx +51 -0
  68. package/src/components/Dropdown/index.tsx +201 -0
  69. package/src/components/ExternalPill/index.tsx +58 -0
  70. package/src/components/Facepile/index.tsx +309 -0
  71. package/src/components/GradientCircle/gradientCircle.css +34 -0
  72. package/src/components/GradientCircle/index.tsx +143 -0
  73. package/src/components/Grid/index.tsx +150 -0
  74. package/src/components/Heading/index.tsx +54 -0
  75. package/src/components/HighlightedText/index.tsx +152 -0
  76. package/src/components/Icon/customIcons/createCustomLucideIcon.ts +25 -0
  77. package/src/components/Icon/customIcons/gems.ts +26 -0
  78. package/{dist/go-CiWl_aXI.mjs → src/components/Icon/customIcons/go.ts} +21 -19
  79. package/src/components/Icon/customIcons/index.ts +11 -0
  80. package/{dist/maven-DhmnGXoB.mjs → src/components/Icon/customIcons/maven.ts} +17 -15
  81. package/src/components/Icon/customIcons/npm.ts +19 -0
  82. package/{dist/nuget-5a2icRS2.mjs → src/components/Icon/customIcons/nuget.ts} +17 -15
  83. package/src/components/Icon/customIcons/packagist.ts +124 -0
  84. package/{dist/pypi-DsuRYjdK.mjs → src/components/Icon/customIcons/pypi.ts} +16 -14
  85. package/src/components/Icon/index.tsx +83 -0
  86. package/src/components/Icon/isIconName.ts +10 -0
  87. package/src/components/Icon/names.ts +14 -0
  88. package/src/components/IconButton/index.tsx +51 -0
  89. package/src/components/Input/index.tsx +98 -0
  90. package/src/components/KeyHint/index.tsx +118 -0
  91. package/src/components/LanguageIndicator/index.tsx +68 -0
  92. package/src/components/Link/index.tsx +153 -0
  93. package/src/components/LoggedInUserMenu/index.tsx +116 -0
  94. package/src/components/Logo/Animated.tsx +191 -0
  95. package/src/components/Logo/index.tsx +17 -0
  96. package/src/components/Logo/speakeasy-logo.riv +0 -0
  97. package/src/components/Logo/svgs/index.tsx +126 -0
  98. package/src/components/Modal/index.tsx +104 -0
  99. package/src/components/PageHeader/index.tsx +227 -0
  100. package/src/components/PageHeader/styles.module.css +27 -0
  101. package/src/components/Popover/index.tsx +35 -0
  102. package/src/components/PromptInput/index.tsx +372 -0
  103. package/src/components/PullRequestLink/index.tsx +64 -0
  104. package/src/components/ResizablePanel/index.tsx +119 -0
  105. package/src/components/Score/index.module.css +32 -0
  106. package/src/components/Score/index.tsx +268 -0
  107. package/src/components/ScrollArea/index.tsx +48 -0
  108. package/src/components/SegmentedButton/index.module.css +19 -0
  109. package/src/components/SegmentedButton/index.tsx +101 -0
  110. package/src/components/Select/index.tsx +159 -0
  111. package/src/components/Separator/index.tsx +23 -0
  112. package/src/components/Skeleton/index.tsx +61 -0
  113. package/src/components/Skeleton/skeleton.css +52 -0
  114. package/src/components/Stack/index.tsx +137 -0
  115. package/src/components/Subnav/index.tsx +315 -0
  116. package/src/components/Switch/index.tsx +29 -0
  117. package/src/components/Table/context/context.tsx +19 -0
  118. package/src/components/Table/context/tableProvider.tsx +39 -0
  119. package/src/components/Table/index.tsx +707 -0
  120. package/src/components/Table/styles.module.css +25 -0
  121. package/src/components/Tabs/index.tsx +87 -0
  122. package/src/components/TargetLanguageIcon/index.tsx +84 -0
  123. package/src/components/Text/index.tsx +59 -0
  124. package/src/components/ThemeSwitcher/index.tsx +118 -0
  125. package/src/components/Timeline/index.tsx +290 -0
  126. package/src/components/Tooltip/index.tsx +41 -0
  127. package/src/components/UserAvatar/index.tsx +87 -0
  128. package/src/components/UserAvatar/sizeMap.ts +12 -0
  129. package/src/components/Wizard/index.tsx +208 -0
  130. package/src/components/Wizard/types.ts +17 -0
  131. package/src/components/WorkspaceSelector/CreateOrg.tsx +95 -0
  132. package/src/components/WorkspaceSelector/CreateWorkspace.tsx +196 -0
  133. package/src/components/WorkspaceSelector/OrgList.tsx +115 -0
  134. package/src/components/WorkspaceSelector/OrgSelector.tsx +207 -0
  135. package/src/components/WorkspaceSelector/RecentWorkspaces.tsx +83 -0
  136. package/src/components/WorkspaceSelector/ScrollingList.tsx +84 -0
  137. package/src/components/WorkspaceSelector/SearchBox.tsx +40 -0
  138. package/src/components/WorkspaceSelector/WorkspaceItem.tsx +37 -0
  139. package/src/components/WorkspaceSelector/WorkspaceList.tsx +107 -0
  140. package/src/components/WorkspaceSelector/index.tsx +400 -0
  141. package/src/components/WorkspaceSelector/styles.css +74 -0
  142. package/src/components/__beta__/CLIWizard/index.tsx +357 -0
  143. package/src/components/__beta__/CLIWizard/terminal-command.tsx +108 -0
  144. package/src/components/__beta__/CLIWizard/terminal.tsx +83 -0
  145. package/src/components/__beta__/README.md +3 -0
  146. package/src/components/index.mdx +38 -0
  147. package/src/context/ConfigContext.tsx +43 -0
  148. package/src/context/ModalContext.tsx +118 -0
  149. package/src/context/theme.ts +1 -0
  150. package/src/hooks/useAppLayout.ts +10 -0
  151. package/src/hooks/useConfig.ts +10 -0
  152. package/src/hooks/useIsMounted.ts +13 -0
  153. package/src/hooks/useModal.tsx +10 -0
  154. package/src/hooks/useTailwindBreakpoint.ts +47 -0
  155. package/src/hooks/useTheme.ts +13 -0
  156. package/src/index.ts +234 -0
  157. package/src/lib/assert.ts +9 -0
  158. package/src/lib/codeUtils.ts +177 -0
  159. package/src/lib/debounce.ts +9 -0
  160. package/src/lib/responsiveMappers.ts +69 -0
  161. package/src/lib/responsiveUtils.ts +23 -0
  162. package/src/lib/storybookUtils.tsx +26 -0
  163. package/src/lib/typeUtils.ts +109 -0
  164. package/src/lib/utils.ts +85 -0
  165. package/src/styles/codeSyntax.css +59 -0
  166. package/src/styles/globals.css +51 -0
  167. package/src/types.ts +200 -0
  168. package/src/utilities.css +347 -6
  169. package/src/vite-env.d.ts +6 -0
  170. package/types/utilities.d.ts +43 -1
  171. package/dist/components/AIChat/AIChatContainer.d.ts +0 -25
  172. package/dist/components/AIChat/AIChatMessage.d.ts +0 -19
  173. package/dist/components/AIChat/AIChatMessageComposer.d.ts +0 -22
  174. package/dist/components/AIChat/AIChatMessageList.d.ts +0 -6
  175. package/dist/components/AIChat/AIChatModelSelector.d.ts +0 -14
  176. package/dist/components/AIChat/componentsTypes.d.ts +0 -11
  177. package/dist/components/AIChat/context.d.ts +0 -3
  178. package/dist/components/AIChat/index.d.ts +0 -12
  179. package/dist/components/AIChat/parts/AIChatMessageFilePart.d.ts +0 -7
  180. package/dist/components/AIChat/parts/AIChatMessageReasoningPart.d.ts +0 -5
  181. package/dist/components/AIChat/parts/AIChatMessageSourcePart.d.ts +0 -9
  182. package/dist/components/AIChat/parts/AIChatMessageTextPart.d.ts +0 -5
  183. package/dist/components/AIChat/parts/AIChatMessageToolInvocationPart.d.ts +0 -6
  184. package/dist/components/AIChat/parts/AIChatMessageToolPart.d.ts +0 -33
  185. package/dist/components/AIChat/parts/AIChatMessageToolResultPart.d.ts +0 -5
  186. package/dist/components/AIChat/toolCallApproval.d.ts +0 -15
  187. package/dist/components/AIChat/types.d.ts +0 -78
  188. package/dist/components/ActionBar/index.d.ts +0 -36
  189. package/dist/components/Alert/index.d.ts +0 -18
  190. package/dist/components/Alert/types.d.ts +0 -4
  191. package/dist/components/Badge/index.d.ts +0 -10
  192. package/dist/components/Button/index.d.ts +0 -11
  193. package/dist/components/Card/index.d.ts +0 -47
  194. package/dist/components/CodeEditorLayout/index.d.ts +0 -101
  195. package/dist/components/CodePlayground/index.d.ts +0 -108
  196. package/dist/components/CodePlayground/lineNumbers.d.ts +0 -2
  197. package/dist/components/CodePlayground/tokenTransitions.d.ts +0 -2
  198. package/dist/components/CodePlayground/wordWrap.d.ts +0 -2
  199. package/dist/components/CodeSnippet/index.d.ts +0 -50
  200. package/dist/components/Combobox/index.d.ts +0 -35
  201. package/dist/components/Command/index.d.ts +0 -80
  202. package/dist/components/Container/index.d.ts +0 -9
  203. package/dist/components/ContextDropdown/index.d.ts +0 -7
  204. package/dist/components/ContextDropdown/provider.d.ts +0 -22
  205. package/dist/components/ContextDropdown/useModal.d.ts +0 -11
  206. package/dist/components/Dialog/index.d.ts +0 -19
  207. package/dist/components/DragNDrop/DragNDropArea.d.ts +0 -8
  208. package/dist/components/DragNDrop/DragOverlay.d.ts +0 -1
  209. package/dist/components/DragNDrop/Draggable.d.ts +0 -29
  210. package/dist/components/DragNDrop/Droppable.d.ts +0 -28
  211. package/dist/components/Dropdown/index.d.ts +0 -27
  212. package/dist/components/ExternalPill/index.d.ts +0 -12
  213. package/dist/components/Facepile/index.d.ts +0 -16
  214. package/dist/components/GradientCircle/index.d.ts +0 -10
  215. package/dist/components/Grid/index.d.ts +0 -80
  216. package/dist/components/Heading/index.d.ts +0 -12
  217. package/dist/components/HighlightedText/index.d.ts +0 -19
  218. package/dist/components/Icon/customIcons/createCustomLucideIcon.d.ts +0 -3
  219. package/dist/components/Icon/customIcons/gems.d.ts +0 -2
  220. package/dist/components/Icon/customIcons/go.d.ts +0 -2
  221. package/dist/components/Icon/customIcons/index.d.ts +0 -10
  222. package/dist/components/Icon/customIcons/maven.d.ts +0 -2
  223. package/dist/components/Icon/customIcons/npm.d.ts +0 -2
  224. package/dist/components/Icon/customIcons/nuget.d.ts +0 -2
  225. package/dist/components/Icon/customIcons/packagist.d.ts +0 -2
  226. package/dist/components/Icon/customIcons/pypi.d.ts +0 -2
  227. package/dist/components/Icon/index.d.ts +0 -10
  228. package/dist/components/Icon/isIconName.d.ts +0 -2
  229. package/dist/components/Icon/names.d.ts +0 -6
  230. package/dist/components/Input/index.d.ts +0 -8
  231. package/dist/components/KeyHint/index.d.ts +0 -16
  232. package/dist/components/LanguageIndicator/index.d.ts +0 -7
  233. package/dist/components/Link/index.d.ts +0 -19
  234. package/dist/components/LoggedInUserMenu/index.d.ts +0 -17
  235. package/dist/components/Logo/Animated.d.ts +0 -7
  236. package/dist/components/Logo/index.d.ts +0 -7
  237. package/dist/components/Logo/svgs/index.d.ts +0 -6
  238. package/dist/components/Navbar/Slim.d.ts +0 -33
  239. package/dist/components/Navbar/index.d.ts +0 -15
  240. package/dist/components/PageHeader/index.d.ts +0 -45
  241. package/dist/components/Popover/index.d.ts +0 -8
  242. package/dist/components/PromptInput/index.d.ts +0 -55
  243. package/dist/components/PullRequestLink/index.d.ts +0 -10
  244. package/dist/components/ResizablePanel/index.d.ts +0 -26
  245. package/dist/components/Score/index.d.ts +0 -37
  246. package/dist/components/ScrollArea/index.d.ts +0 -5
  247. package/dist/components/Select/index.d.ts +0 -13
  248. package/dist/components/Separator/index.d.ts +0 -6
  249. package/dist/components/Skeleton/index.d.ts +0 -27
  250. package/dist/components/Stack/index.d.ts +0 -33
  251. package/dist/components/Subnav/index.d.ts +0 -12
  252. package/dist/components/Switch/index.d.ts +0 -4
  253. package/dist/components/Table/context/context.d.ts +0 -8
  254. package/dist/components/Table/context/tableProvider.d.ts +0 -6
  255. package/dist/components/Table/index.d.ts +0 -94
  256. package/dist/components/Tabs/index.d.ts +0 -21
  257. package/dist/components/TargetLanguageIcon/index.d.ts +0 -7
  258. package/dist/components/Text/index.d.ts +0 -19
  259. package/dist/components/ThemeSwitcher/index.d.ts +0 -5
  260. package/dist/components/Tooltip/index.d.ts +0 -8
  261. package/dist/components/UserAvatar/index.d.ts +0 -9
  262. package/dist/components/UserAvatar/sizeMap.d.ts +0 -3
  263. package/dist/components/Wizard/index.d.ts +0 -19
  264. package/dist/components/Wizard/types.d.ts +0 -15
  265. package/dist/components/WorkspaceSelector/CreateOrg.d.ts +0 -6
  266. package/dist/components/WorkspaceSelector/CreateWorkspace.d.ts +0 -17
  267. package/dist/components/WorkspaceSelector/OrgList.d.ts +0 -11
  268. package/dist/components/WorkspaceSelector/OrgSelector.d.ts +0 -13
  269. package/dist/components/WorkspaceSelector/RecentWorkspaces.d.ts +0 -11
  270. package/dist/components/WorkspaceSelector/ScrollingList.d.ts +0 -21
  271. package/dist/components/WorkspaceSelector/SearchBox.d.ts +0 -9
  272. package/dist/components/WorkspaceSelector/WorkspaceItem.d.ts +0 -9
  273. package/dist/components/WorkspaceSelector/WorkspaceList.d.ts +0 -10
  274. package/dist/components/WorkspaceSelector/index.d.ts +0 -34
  275. package/dist/components/__beta__/CLIWizard/index.d.ts +0 -21
  276. package/dist/components/__beta__/CLIWizard/terminal-command.d.ts +0 -19
  277. package/dist/components/__beta__/CLIWizard/terminal.d.ts +0 -26
  278. package/dist/context/ConfigContext.d.ts +0 -18
  279. package/dist/context/theme.d.ts +0 -1
  280. package/dist/createCustomLucideIcon-YlrRX5h9.mjs +0 -19
  281. package/dist/createCustomLucideIcon-YlrRX5h9.mjs.map +0 -1
  282. package/dist/gems-BcsO9cXq.mjs +0 -24
  283. package/dist/gems-BcsO9cXq.mjs.map +0 -1
  284. package/dist/github-kgjMtfE7.mjs +0 -11
  285. package/dist/github-kgjMtfE7.mjs.map +0 -1
  286. package/dist/go-CiWl_aXI.mjs.map +0 -1
  287. package/dist/hooks/useConfig.d.ts +0 -2
  288. package/dist/hooks/useIsMounted.d.ts +0 -1
  289. package/dist/hooks/useTailwindBreakpoint.d.ts +0 -3
  290. package/dist/hooks/useTheme.d.ts +0 -6
  291. package/dist/index-COXZ9O-g.mjs +0 -50882
  292. package/dist/index-COXZ9O-g.mjs.map +0 -1
  293. package/dist/index.d.ts +0 -73
  294. package/dist/lib/assert.d.ts +0 -2
  295. package/dist/lib/codeUtils.d.ts +0 -35
  296. package/dist/lib/debounce.d.ts +0 -1
  297. package/dist/lib/responsiveMappers.d.ts +0 -10
  298. package/dist/lib/responsiveUtils.d.ts +0 -3
  299. package/dist/lib/storybookUtils.d.ts +0 -5
  300. package/dist/lib/typeUtils.d.ts +0 -24
  301. package/dist/lib/utils.d.ts +0 -23
  302. package/dist/lucide-icons-BDw0imyx.mjs +0 -28054
  303. package/dist/lucide-icons-BDw0imyx.mjs.map +0 -1
  304. package/dist/maven-DhmnGXoB.mjs.map +0 -1
  305. package/dist/maven-W_nkSDNW.mjs +0 -107
  306. package/dist/maven-W_nkSDNW.mjs.map +0 -1
  307. package/dist/moonshine.es.js +0 -114
  308. package/dist/moonshine.es.js.map +0 -1
  309. package/dist/npm-BWTcVvFH.mjs +0 -11
  310. package/dist/npm-BWTcVvFH.mjs.map +0 -1
  311. package/dist/npm-CvQ4GKW4.mjs +0 -17
  312. package/dist/npm-CvQ4GKW4.mjs.map +0 -1
  313. package/dist/nuget-5a2icRS2.mjs.map +0 -1
  314. package/dist/nuget-CV5HU1JR.mjs +0 -11
  315. package/dist/nuget-CV5HU1JR.mjs.map +0 -1
  316. package/dist/packagist-CET6q9hi.mjs +0 -118
  317. package/dist/packagist-CET6q9hi.mjs.map +0 -1
  318. package/dist/packagist-D01fn9N_.mjs +0 -11
  319. package/dist/packagist-D01fn9N_.mjs.map +0 -1
  320. package/dist/pypi-DLh6kIJe.mjs +0 -11
  321. package/dist/pypi-DLh6kIJe.mjs.map +0 -1
  322. package/dist/pypi-DsuRYjdK.mjs.map +0 -1
  323. package/dist/rubygems-DeiNjcDV.mjs +0 -11
  324. package/dist/rubygems-DeiNjcDV.mjs.map +0 -1
  325. package/dist/speakeasy-logo-ByBTXLWb.mjs +0 -5
  326. package/dist/speakeasy-logo-ByBTXLWb.mjs.map +0 -1
  327. package/dist/style.css +0 -1
  328. package/dist/terraform-C4aktQ0o.mjs +0 -11
  329. package/dist/terraform-C4aktQ0o.mjs.map +0 -1
  330. package/dist/types.d.ts +0 -80
@@ -0,0 +1,87 @@
1
+ import { cn, getResponsiveClasses } from '../../lib/utils'
2
+ import { ResponsiveValue, Size } from '../../types'
3
+ import { userAvatarSizeMap } from './sizeMap'
4
+ import useTailwindBreakpoint from '../../hooks/useTailwindBreakpoint'
5
+ import { resolveSizeForBreakpoint } from '../../lib/responsiveUtils'
6
+ import { userAvatarSizeMapper } from './sizeMap'
7
+
8
+ export interface UserAvatarProps {
9
+ name: string
10
+ imageUrl?: string
11
+ size?: ResponsiveValue<Size>
12
+ border?: boolean
13
+ className?: string
14
+ }
15
+
16
+ const fallbackColors = [
17
+ 'bg-red-500',
18
+ 'bg-orange-500',
19
+ 'bg-yellow-500',
20
+ 'bg-green-500',
21
+ 'bg-blue-500',
22
+ 'bg-purple-500',
23
+ 'bg-pink-500',
24
+ ]
25
+
26
+ // deterministically returns a color based on the first letter of the name
27
+ function getFallbackColor(name: string | undefined) {
28
+ if (!name) return 'bg-gray-900'
29
+ const firstLetter = name[0].toLowerCase()
30
+
31
+ const index = firstLetter.charCodeAt(0) - 'a'.charCodeAt(0)
32
+ return fallbackColors[index % fallbackColors.length]
33
+ }
34
+
35
+ export function UserAvatar({
36
+ name,
37
+ imageUrl,
38
+ size = 'medium',
39
+ border = false,
40
+ className,
41
+ }: UserAvatarProps) {
42
+ const breakpoint = useTailwindBreakpoint()
43
+
44
+ const resolvedSize = resolveSizeForBreakpoint(breakpoint, size, 'medium')
45
+ const sizeValue = userAvatarSizeMap[resolvedSize]
46
+
47
+ const hasImage = !!imageUrl
48
+
49
+ return (
50
+ <div
51
+ className={cn(
52
+ 'flex items-center justify-center overflow-hidden rounded-full bg-gray-200',
53
+ getResponsiveClasses(size, userAvatarSizeMapper),
54
+ !hasImage && getFallbackColor(name),
55
+ border && 'border-background border-2',
56
+ className
57
+ )}
58
+ >
59
+ {hasImage ? (
60
+ <img
61
+ src={imageUrl}
62
+ alt={name}
63
+ className="h-full w-full object-cover object-center select-none"
64
+ />
65
+ ) : (
66
+ <svg
67
+ className="h-full w-full select-none"
68
+ viewBox={`0 0 ${sizeValue} ${sizeValue}`}
69
+ preserveAspectRatio="xMidYMid meet"
70
+ >
71
+ <text
72
+ x="50%"
73
+ y="50%"
74
+ textAnchor="middle"
75
+ alignmentBaseline="middle"
76
+ fill="white"
77
+ fontSize={sizeValue * 0.75}
78
+ dy="0.075em"
79
+ fontWeight="semibold"
80
+ >
81
+ {name[0] || '✖️'}
82
+ </text>
83
+ </svg>
84
+ )}
85
+ </div>
86
+ )
87
+ }
@@ -0,0 +1,12 @@
1
+ import { Size } from '../../types'
2
+
3
+ export const userAvatarSizeMap: Record<Size, number> = {
4
+ small: 8,
5
+ medium: 12,
6
+ large: 16,
7
+ xl: 24,
8
+ '2xl': 32,
9
+ }
10
+
11
+ export const userAvatarSizeMapper = (size: Size) =>
12
+ `size-${userAvatarSizeMap[size]}`
@@ -0,0 +1,208 @@
1
+ import * as React from 'react'
2
+ import { cn } from '../../lib/utils'
3
+ import { CodeSnippet, Heading, Text } from '../../index'
4
+ import { useMemo } from 'react'
5
+ import { WizardStep } from './types'
6
+
7
+ export interface WizardProps {
8
+ /**
9
+ * The steps to display in the wizard
10
+ */
11
+ steps: WizardStep[]
12
+
13
+ /**
14
+ * The current step number, starting from 1
15
+ */
16
+ currentStep: number
17
+
18
+ /**
19
+ * The steps that have been completed, starting from 1
20
+ */
21
+ completedSteps: number[]
22
+
23
+ headerContent: (
24
+ completedSteps: number[],
25
+ steps: WizardStep[]
26
+ ) => React.ReactNode
27
+
28
+ className?: string
29
+ }
30
+
31
+ export function Wizard({
32
+ steps,
33
+ currentStep,
34
+ completedSteps,
35
+ headerContent,
36
+ className,
37
+ }: WizardProps) {
38
+ const [stepHeights, setStepHeights] = React.useState<Map<number, number>>(
39
+ new Map()
40
+ )
41
+ const stepRefs = React.useRef<Map<number, HTMLDivElement | null>>(new Map())
42
+
43
+ React.useEffect(() => {
44
+ const currentElement = stepRefs.current.get(currentStep)
45
+ if (currentElement) {
46
+ setStepHeights((prev) => {
47
+ const newMap = new Map(prev)
48
+ newMap.set(currentStep, currentElement.clientHeight)
49
+ return newMap
50
+ })
51
+ }
52
+ }, [currentStep, completedSteps])
53
+
54
+ // Add ResizeObserver to monitor size changes
55
+ React.useEffect(() => {
56
+ const resizeObserver = new ResizeObserver((entries) => {
57
+ entries.forEach((entry) => {
58
+ const stepNumber = Array.from(stepRefs.current.entries()).find(
59
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
60
+ ([_, el]) => el === entry.target
61
+ )?.[0]
62
+
63
+ if (stepNumber) {
64
+ setStepHeights((prev) => {
65
+ const newMap = new Map(prev)
66
+ newMap.set(stepNumber, entry.target.clientHeight)
67
+ return newMap
68
+ })
69
+ }
70
+ })
71
+ })
72
+
73
+ // Observe all step elements
74
+ stepRefs.current.forEach((element) => {
75
+ if (element) {
76
+ resizeObserver.observe(element)
77
+ }
78
+ })
79
+
80
+ return () => {
81
+ resizeObserver.disconnect()
82
+ }
83
+ }, []) // Empty dependency array since we want to set up the observer once
84
+
85
+ const getStepStatus = (index: number) => {
86
+ if (completedSteps.includes(index + 1)) return 'completed'
87
+ if (index + 1 === currentStep) return 'current'
88
+ return 'upcoming'
89
+ }
90
+
91
+ const trackHeight = useMemo(() => {
92
+ return Array.from(
93
+ {
94
+ length:
95
+ completedSteps.length === steps.length
96
+ ? currentStep
97
+ : currentStep - 1,
98
+ },
99
+ (_, i) => i + 1
100
+ )
101
+ .map((step) => {
102
+ const height = stepHeights.get(step) || 0
103
+ // Add the top and bottom padding (py-4 = 1rem * 2 = 32px total)
104
+ return height + 16
105
+ })
106
+ .reduce((acc, curr) => acc + curr, 0)
107
+ }, [currentStep, stepHeights])
108
+
109
+ return (
110
+ <div className={cn('max-w-screen-x flex flex-col gap-2', className)}>
111
+ <div className="border-b p-6">
112
+ <div className="flex items-center justify-between">
113
+ <div className="space-y-1">
114
+ {headerContent(completedSteps, steps)}
115
+ </div>
116
+ </div>
117
+ </div>
118
+
119
+ <div className="relative mt-8 pl-3">
120
+ <div className="bg-border absolute top-0 bottom-0 left-7 w-px overflow-y-hidden">
121
+ <div
122
+ className="bg-primary absolute top-0 left-0 w-full transition-all duration-500"
123
+ style={{
124
+ height: trackHeight,
125
+ }}
126
+ />
127
+ </div>
128
+
129
+ <div className="flex flex-col gap-8">
130
+ {steps.map((step, index) => {
131
+ const status = getStepStatus(index)
132
+ const stepNumber = index + 1
133
+
134
+ return (
135
+ <div
136
+ key={index}
137
+ ref={(el) => stepRefs.current.set(stepNumber, el)}
138
+ >
139
+ <div
140
+ className={cn(
141
+ 'relative pl-16',
142
+ status === 'completed' && 'text-body'
143
+ )}
144
+ >
145
+ <div className="flex items-center gap-2">
146
+ <div
147
+ className={cn(
148
+ 'absolute left-0 flex h-8 w-8 items-center justify-center rounded-full text-sm font-semibold',
149
+ // TODO: update these to use new color tokens
150
+ status === 'completed' &&
151
+ 'bg-success-default text-highlight-fixed-light',
152
+ status === 'current' &&
153
+ 'bg-surface-primary-inverse text-default-inverse scale-110',
154
+ status === 'upcoming' && 'bg-muted text-muted'
155
+ )}
156
+ >
157
+ {stepNumber}
158
+ </div>
159
+
160
+ {/* TODO: is this the best way to handle the opacity? */}
161
+ <div className={cn(status === 'upcoming' && 'opacity-50')}>
162
+ <Heading variant="md" as="h2">
163
+ {step.title}
164
+ </Heading>
165
+ </div>
166
+ </div>
167
+
168
+ {/* TODO: is this the best way to handle the opacity? */}
169
+ <div
170
+ className={cn(
171
+ 'mt-2 mb-4',
172
+ status === 'upcoming' && 'opacity-50'
173
+ )}
174
+ >
175
+ <Text muted>{step.description}</Text>
176
+ </div>
177
+
178
+ <div
179
+ className={cn(
180
+ 'mt-8 flex w-full flex-col gap-5',
181
+ status === 'upcoming' && 'opacity-50'
182
+ )}
183
+ >
184
+ {/* TODO: update this to CodeBlock component */}
185
+ {status === 'current' &&
186
+ step.commands?.map((command, cmdIndex) => (
187
+ <CodeSnippet
188
+ key={cmdIndex}
189
+ code={command.code}
190
+ language={command.language}
191
+ onSelectOrCopy={() =>
192
+ command.onSelectOrCopy?.(command.id)
193
+ }
194
+ copyable
195
+ fontSize="small"
196
+ shimmer={command.active}
197
+ />
198
+ ))}
199
+ </div>
200
+ </div>
201
+ </div>
202
+ )
203
+ })}
204
+ </div>
205
+ </div>
206
+ </div>
207
+ )
208
+ }
@@ -0,0 +1,17 @@
1
+ import { ProgrammingLanguage } from '../../types'
2
+
3
+ export interface WizardCommand {
4
+ id: string
5
+ code: string
6
+ language: ProgrammingLanguage
7
+ comment?: string
8
+ active?: boolean
9
+ path?: string
10
+ onSelectOrCopy?: (id: string) => void
11
+ }
12
+
13
+ export interface WizardStep {
14
+ title: string
15
+ description: string
16
+ commands?: WizardCommand[]
17
+ }
@@ -0,0 +1,95 @@
1
+ import { useRef, useState, useEffect } from 'react'
2
+ import { Org } from '.'
3
+ import { Command } from '../Command'
4
+ import { Stack } from '../Stack'
5
+ import { GradientCircle } from '../GradientCircle'
6
+ import { Separator } from '../Separator'
7
+ import { Text } from '../Text'
8
+ import { Button } from '../Button'
9
+ import { Heading } from '../../index'
10
+
11
+ interface CreateOrgProps {
12
+ onSubmit: (name: string) => Promise<Org>
13
+ }
14
+
15
+ export function CreateOrg({ onSubmit }: CreateOrgProps) {
16
+ const [companyName, setCompanyName] = useState('')
17
+ const inputRef = useRef<HTMLInputElement>(null)
18
+
19
+ useEffect(() => {
20
+ if (inputRef.current) {
21
+ inputRef.current.focus()
22
+ }
23
+ }, [])
24
+
25
+ return (
26
+ <Command className="relative">
27
+ <div className="flex h-full w-full flex-row items-center">
28
+ <div className="flex w-1/3 flex-col items-center justify-center gap-4 px-8 text-center">
29
+ <div className="flex flex-col items-center justify-center gap-4">
30
+ <GradientCircle
31
+ name={companyName}
32
+ size="2xl"
33
+ transition
34
+ showInitial
35
+ />
36
+ <Stack align="center" gap={2}>
37
+ <Heading variant="xl">Create new company</Heading>
38
+ <div className="max-w-64">
39
+ <Text muted>
40
+ Once you have created your company, we'll take you through
41
+ some onboarding steps to get you started with Speakeasy.
42
+ </Text>
43
+ </div>
44
+ </Stack>
45
+ </div>
46
+ </div>
47
+
48
+ <Separator orientation="vertical" />
49
+
50
+ <div className="flex w-2/3 flex-col items-center justify-center px-8">
51
+ <div className="flex max-w-lg flex-col">
52
+ <div className="flex flex-col gap-4">
53
+ <Stack align="start" gap={2}>
54
+ <Text variant="lg">Enter your company name</Text>
55
+ <Text muted>
56
+ We will automatically generate a unique, URL-friendly slug
57
+ based off your company name.
58
+ </Text>
59
+ </Stack>
60
+ </div>
61
+ <div className="flex flex-col">
62
+ <div className="focus-within:outline-muted/50 shadow-muted bg-input/10 border-neutral-softest ease-in-out-expo mt-5 flex w-full max-w-[660px] flex-row items-center justify-stretch gap-2 rounded-md border px-4 py-1 transition-[border-color] duration-500 focus-within:shadow-sm focus-within:outline focus-within:outline-offset-0 data-[invalid=true]:border-red-400/75">
63
+ <div className="flex w-full">
64
+ <input
65
+ type="text"
66
+ role="textbox"
67
+ name="companyName"
68
+ pattern="^[a-z0-9]+(?:-[a-z0-9]+)*$"
69
+ ref={inputRef}
70
+ placeholder="Your company name"
71
+ value={companyName}
72
+ onChange={(e) => setCompanyName(e.target.value)}
73
+ className="border-neutral-softest text-foreground/80 placeholder:text-muted-foreground/50 ring-offset-background text-md flex h-10 w-full min-w-fit flex-1 flex-grow bg-transparent px-2 py-1.5 pl-0 text-lg outline-none"
74
+ />
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </div>
81
+
82
+ <div className="border-neutral-softest bg-background flex border-t px-8 py-4">
83
+ <div className="ml-auto">
84
+ <Button
85
+ variant="secondary"
86
+ disabled={!companyName}
87
+ onClick={() => onSubmit(companyName)}
88
+ >
89
+ Next
90
+ </Button>
91
+ </div>
92
+ </div>
93
+ </Command>
94
+ )
95
+ }
@@ -0,0 +1,196 @@
1
+ import React, { useCallback, useEffect, useState } from 'react'
2
+ import { Org } from '.'
3
+ import { Command } from '../Command'
4
+ import { Text } from '../Text'
5
+ import { Icon } from '../Icon'
6
+ import { Button, Heading, Stack } from '../../index'
7
+ import { Separator } from '../Separator'
8
+ import { GradientCircle } from '../GradientCircle'
9
+
10
+ import { cn } from '../../lib/utils'
11
+ import { OrgSelector } from './OrgSelector'
12
+
13
+ export interface CreateResult {
14
+ success: boolean
15
+ error?: string
16
+ }
17
+
18
+ interface CreateWorkspaceProps {
19
+ open: boolean
20
+ selectedOrg: Org
21
+ allOrgs: Org[]
22
+ onBack?: () => void
23
+ onSubmit: (org: Org, workspaceName: string) => Promise<CreateResult>
24
+ newWorkspaceName: string
25
+ setNewWorkspaceName: (name: string) => void
26
+ backButtonEnabled?: boolean
27
+ }
28
+
29
+ export function CreateWorkspace({
30
+ open,
31
+ selectedOrg,
32
+ allOrgs,
33
+ onBack,
34
+ onSubmit,
35
+ newWorkspaceName,
36
+ setNewWorkspaceName,
37
+ backButtonEnabled = true,
38
+ }: CreateWorkspaceProps) {
39
+ const createInputRef = React.useRef<HTMLInputElement>(null)
40
+ const [isInvalid, setIsInvalid] = useState(false)
41
+ const [currentOrg, setCurrentOrg] = useState(selectedOrg)
42
+ const [isSubmitting, setIsSubmitting] = useState(false)
43
+ const [error, setError] = useState<string | null>(null)
44
+
45
+ React.useEffect(() => {
46
+ if (open) {
47
+ setTimeout(() => {
48
+ createInputRef.current?.focus()
49
+ }, 300)
50
+ }
51
+ }, [open])
52
+
53
+ useEffect(() => {
54
+ // Focus the input when the org changes
55
+ focusInput()
56
+ }, [currentOrg])
57
+
58
+ const focusInput = () => {
59
+ createInputRef.current?.focus()
60
+ }
61
+
62
+ const handleSubmit = async () => {
63
+ setIsSubmitting(true)
64
+ const result = await onSubmit(currentOrg, newWorkspaceName)
65
+ setIsSubmitting(false)
66
+ if (!result.success) {
67
+ setError(result.error ?? 'Unknown error')
68
+ }
69
+ }
70
+
71
+ const handleChange = useCallback(
72
+ (e: React.ChangeEvent<HTMLInputElement>) => {
73
+ setNewWorkspaceName(e.target.value)
74
+ setIsInvalid(!e.target.validity.valid)
75
+ },
76
+ [setNewWorkspaceName, setIsInvalid]
77
+ )
78
+
79
+ return (
80
+ <Command className="relative">
81
+ <div className="flex h-full w-full flex-row items-center">
82
+ <div className="flex w-1/3 flex-col items-center justify-center gap-4 px-8 text-center">
83
+ <div className="flex flex-col items-center justify-center gap-4">
84
+ <GradientCircle name={currentOrg.label} size="2xl" showInitial />
85
+ <Stack align="center" gap={2}>
86
+ <Heading variant="xl">Create new workspace</Heading>
87
+ <div className="max-w-64">
88
+ <Text muted>
89
+ Workspaces are used to organize your SDK targets into logical
90
+ groups.
91
+ </Text>
92
+ </div>
93
+ </Stack>
94
+ </div>
95
+ </div>
96
+
97
+ <Separator orientation="vertical" />
98
+
99
+ <div className="flex w-2/3 flex-col items-center justify-center px-8">
100
+ <div className="flex max-w-lg flex-col">
101
+ <div className="flex flex-col gap-4">
102
+ <Stack align="start" gap={2}>
103
+ <Text variant="lg">Choose your workspace name</Text>
104
+ <Text muted>
105
+ Enter a name for your new workspace. Names must be in slug
106
+ format; only lowercase letters, numbers, and hyphens are
107
+ allowed.
108
+ </Text>
109
+ </Stack>
110
+ </div>
111
+ <div className="flex flex-col">
112
+ <div
113
+ className="focus-within:outline-muted/50 shadow-muted bg-input/10 border-neutral-softest ease-in-out-expo mt-5 flex w-full max-w-[660px] flex-row items-center justify-stretch gap-2 rounded-md border px-4 py-1 transition-[border-color] duration-500 focus-within:shadow-sm focus-within:outline focus-within:outline-1 focus-within:outline-offset-0 data-[invalid=true]:border-red-400/75"
114
+ onClick={focusInput}
115
+ data-invalid={isInvalid}
116
+ >
117
+ {allOrgs.length > 1 ? (
118
+ <OrgSelector
119
+ orgs={allOrgs}
120
+ selectedOrg={currentOrg}
121
+ onSelect={setCurrentOrg}
122
+ />
123
+ ) : (
124
+ <span
125
+ title={currentOrg.slug}
126
+ className={cn(
127
+ 'text-foreground/80 text-lg font-semibold whitespace-pre select-none',
128
+ currentOrg.slug.length > 20 &&
129
+ 'max-w-40 truncate whitespace-pre'
130
+ )}
131
+ >
132
+ {currentOrg.slug}
133
+ </span>
134
+ )}
135
+ <span className="text-muted-foreground/50 mx-2 text-lg select-none">
136
+ /
137
+ </span>
138
+ <div className="flex w-full">
139
+ <input
140
+ ref={createInputRef}
141
+ type="text"
142
+ pattern="^[a-z0-9]+(?:-[a-z0-9]+)*$"
143
+ role="textbox"
144
+ name="workspaceName"
145
+ placeholder="your-new-workspace"
146
+ value={newWorkspaceName}
147
+ onChange={handleChange}
148
+ className="border-neutral-softest text-foreground/80 placeholder:text-muted-foreground/50 ring-offset-background text-md flex h-10 w-full min-w-fit flex-1 flex-grow bg-transparent px-2 py-1.5 pl-0 text-lg outline-none"
149
+ />
150
+ </div>
151
+ </div>
152
+
153
+ <div className="mt-2.5 min-h-6 self-start">
154
+ {newWorkspaceName &&
155
+ !newWorkspaceName.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/) && (
156
+ <div className="text-sm text-red-400/75">
157
+ Workspace names can only contain lowercase letters,
158
+ numbers, and hyphens
159
+ </div>
160
+ )}
161
+ {error && (
162
+ <div className="text-sm text-red-400/75">{error}</div>
163
+ )}
164
+ </div>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+
170
+ <div className="border-neutral-softest bg-background flex border-t px-8 py-4">
171
+ {backButtonEnabled && onBack && (
172
+ <Button variant="secondary" onClick={onBack}>
173
+ <Icon name="chevron-left" size="small" />
174
+ Back
175
+ </Button>
176
+ )}
177
+ <div className="ml-auto">
178
+ <Button
179
+ variant="secondary"
180
+ disabled={
181
+ !newWorkspaceName ||
182
+ !newWorkspaceName.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
183
+ }
184
+ onClick={handleSubmit}
185
+ >
186
+ {isSubmitting ? (
187
+ <Icon name="loader" className="animate-spin" />
188
+ ) : (
189
+ 'Create'
190
+ )}
191
+ </Button>
192
+ </div>
193
+ </div>
194
+ </Command>
195
+ )
196
+ }