@stackframe/react 2.7.20

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 (316) hide show
  1. package/CHANGELOG.md +1415 -0
  2. package/LICENSE +7 -0
  3. package/README.md +26 -0
  4. package/dist/components/credential-sign-in.d.mts +5 -0
  5. package/dist/components/credential-sign-in.d.ts +5 -0
  6. package/dist/components/credential-sign-in.js +103 -0
  7. package/dist/components/credential-sign-in.js.map +1 -0
  8. package/dist/components/credential-sign-up.d.mts +7 -0
  9. package/dist/components/credential-sign-up.d.ts +7 -0
  10. package/dist/components/credential-sign-up.js +138 -0
  11. package/dist/components/credential-sign-up.js.map +1 -0
  12. package/dist/components/elements/form-warning.d.mts +7 -0
  13. package/dist/components/elements/form-warning.d.ts +7 -0
  14. package/dist/components/elements/form-warning.js +39 -0
  15. package/dist/components/elements/form-warning.js.map +1 -0
  16. package/dist/components/elements/maybe-full-page.d.mts +11 -0
  17. package/dist/components/elements/maybe-full-page.d.ts +11 -0
  18. package/dist/components/elements/maybe-full-page.js +74 -0
  19. package/dist/components/elements/maybe-full-page.js.map +1 -0
  20. package/dist/components/elements/separator-with-text.d.mts +7 -0
  21. package/dist/components/elements/separator-with-text.d.ts +7 -0
  22. package/dist/components/elements/separator-with-text.js +41 -0
  23. package/dist/components/elements/separator-with-text.js.map +1 -0
  24. package/dist/components/elements/sidebar-layout.d.mts +19 -0
  25. package/dist/components/elements/sidebar-layout.d.ts +19 -0
  26. package/dist/components/elements/sidebar-layout.js +126 -0
  27. package/dist/components/elements/sidebar-layout.js.map +1 -0
  28. package/dist/components/elements/ssr-layout-effect.d.mts +8 -0
  29. package/dist/components/elements/ssr-layout-effect.d.ts +8 -0
  30. package/dist/components/elements/ssr-layout-effect.js +47 -0
  31. package/dist/components/elements/ssr-layout-effect.js.map +1 -0
  32. package/dist/components/elements/user-avatar.d.mts +13 -0
  33. package/dist/components/elements/user-avatar.d.ts +13 -0
  34. package/dist/components/elements/user-avatar.js +41 -0
  35. package/dist/components/elements/user-avatar.js.map +1 -0
  36. package/dist/components/iframe-preventer.d.mts +8 -0
  37. package/dist/components/iframe-preventer.d.ts +8 -0
  38. package/dist/components/iframe-preventer.js +52 -0
  39. package/dist/components/iframe-preventer.js.map +1 -0
  40. package/dist/components/link.d.mts +14 -0
  41. package/dist/components/link.d.ts +14 -0
  42. package/dist/components/link.js +51 -0
  43. package/dist/components/link.js.map +1 -0
  44. package/dist/components/magic-link-sign-in.d.mts +5 -0
  45. package/dist/components/magic-link-sign-in.d.ts +5 -0
  46. package/dist/components/magic-link-sign-in.js +151 -0
  47. package/dist/components/magic-link-sign-in.js.map +1 -0
  48. package/dist/components/message-cards/known-error-message-card.d.mts +9 -0
  49. package/dist/components/message-cards/known-error-message-card.d.ts +9 -0
  50. package/dist/components/message-cards/known-error-message-card.js +61 -0
  51. package/dist/components/message-cards/known-error-message-card.js.map +1 -0
  52. package/dist/components/message-cards/message-card.d.mts +14 -0
  53. package/dist/components/message-cards/message-card.d.ts +14 -0
  54. package/dist/components/message-cards/message-card.js +45 -0
  55. package/dist/components/message-cards/message-card.js.map +1 -0
  56. package/dist/components/message-cards/predefined-message-card.d.mts +8 -0
  57. package/dist/components/message-cards/predefined-message-card.d.ts +8 -0
  58. package/dist/components/message-cards/predefined-message-card.js +107 -0
  59. package/dist/components/message-cards/predefined-message-card.js.map +1 -0
  60. package/dist/components/oauth-button-group.d.mts +14 -0
  61. package/dist/components/oauth-button-group.d.ts +14 -0
  62. package/dist/components/oauth-button-group.js +43 -0
  63. package/dist/components/oauth-button-group.js.map +1 -0
  64. package/dist/components/oauth-button.d.mts +8 -0
  65. package/dist/components/oauth-button.d.ts +8 -0
  66. package/dist/components/oauth-button.js +210 -0
  67. package/dist/components/oauth-button.js.map +1 -0
  68. package/dist/components/passkey-button.d.mts +7 -0
  69. package/dist/components/passkey-button.d.ts +7 -0
  70. package/dist/components/passkey-button.js +58 -0
  71. package/dist/components/passkey-button.js.map +1 -0
  72. package/dist/components/profile-image-editor.d.mts +11 -0
  73. package/dist/components/profile-image-editor.d.ts +11 -0
  74. package/dist/components/profile-image-editor.js +162 -0
  75. package/dist/components/profile-image-editor.js.map +1 -0
  76. package/dist/components/selected-team-switcher.d.mts +21 -0
  77. package/dist/components/selected-team-switcher.d.ts +21 -0
  78. package/dist/components/selected-team-switcher.js +119 -0
  79. package/dist/components/selected-team-switcher.js.map +1 -0
  80. package/dist/components/team-icon.d.mts +18 -0
  81. package/dist/components/team-icon.d.ts +18 -0
  82. package/dist/components/team-icon.js +39 -0
  83. package/dist/components/team-icon.js.map +1 -0
  84. package/dist/components/user-button.d.mts +15 -0
  85. package/dist/components/user-button.d.ts +15 -0
  86. package/dist/components/user-button.js +120 -0
  87. package/dist/components/user-button.js.map +1 -0
  88. package/dist/components-page/account-settings.d.mts +24 -0
  89. package/dist/components-page/account-settings.d.ts +24 -0
  90. package/dist/components-page/account-settings.js +1095 -0
  91. package/dist/components-page/account-settings.js.map +1 -0
  92. package/dist/components-page/auth-page.d.mts +24 -0
  93. package/dist/components-page/auth-page.d.ts +24 -0
  94. package/dist/components-page/auth-page.js +123 -0
  95. package/dist/components-page/auth-page.js.map +1 -0
  96. package/dist/components-page/email-verification.d.mts +8 -0
  97. package/dist/components-page/email-verification.d.ts +8 -0
  98. package/dist/components-page/email-verification.js +100 -0
  99. package/dist/components-page/email-verification.js.map +1 -0
  100. package/dist/components-page/error-page.d.mts +8 -0
  101. package/dist/components-page/error-page.d.ts +8 -0
  102. package/dist/components-page/error-page.js +97 -0
  103. package/dist/components-page/error-page.js.map +1 -0
  104. package/dist/components-page/forgot-password.d.mts +10 -0
  105. package/dist/components-page/forgot-password.d.ts +10 -0
  106. package/dist/components-page/forgot-password.js +117 -0
  107. package/dist/components-page/forgot-password.js.map +1 -0
  108. package/dist/components-page/magic-link-callback.d.mts +8 -0
  109. package/dist/components-page/magic-link-callback.d.ts +8 -0
  110. package/dist/components-page/magic-link-callback.js +110 -0
  111. package/dist/components-page/magic-link-callback.js.map +1 -0
  112. package/dist/components-page/oauth-callback.d.mts +7 -0
  113. package/dist/components-page/oauth-callback.d.ts +7 -0
  114. package/dist/components-page/oauth-callback.js +75 -0
  115. package/dist/components-page/oauth-callback.js.map +1 -0
  116. package/dist/components-page/password-reset.d.mts +12 -0
  117. package/dist/components-page/password-reset.d.ts +12 -0
  118. package/dist/components-page/password-reset.js +179 -0
  119. package/dist/components-page/password-reset.js.map +1 -0
  120. package/dist/components-page/sign-in.d.mts +10 -0
  121. package/dist/components-page/sign-in.d.ts +10 -0
  122. package/dist/components-page/sign-in.js +44 -0
  123. package/dist/components-page/sign-in.js.map +1 -0
  124. package/dist/components-page/sign-out.d.mts +7 -0
  125. package/dist/components-page/sign-out.d.ts +7 -0
  126. package/dist/components-page/sign-out.js +57 -0
  127. package/dist/components-page/sign-out.js.map +1 -0
  128. package/dist/components-page/sign-up.d.mts +11 -0
  129. package/dist/components-page/sign-up.d.ts +11 -0
  130. package/dist/components-page/sign-up.js +47 -0
  131. package/dist/components-page/sign-up.js.map +1 -0
  132. package/dist/components-page/stack-handler.d.mts +51 -0
  133. package/dist/components-page/stack-handler.d.ts +51 -0
  134. package/dist/components-page/stack-handler.js +244 -0
  135. package/dist/components-page/stack-handler.js.map +1 -0
  136. package/dist/components-page/team-creation.d.mts +7 -0
  137. package/dist/components-page/team-creation.d.ts +7 -0
  138. package/dist/components-page/team-creation.js +92 -0
  139. package/dist/components-page/team-creation.js.map +1 -0
  140. package/dist/components-page/team-invitation.d.mts +8 -0
  141. package/dist/components-page/team-invitation.d.ts +8 -0
  142. package/dist/components-page/team-invitation.js +144 -0
  143. package/dist/components-page/team-invitation.js.map +1 -0
  144. package/dist/esm/components/credential-sign-in.js +79 -0
  145. package/dist/esm/components/credential-sign-in.js.map +1 -0
  146. package/dist/esm/components/credential-sign-up.js +104 -0
  147. package/dist/esm/components/credential-sign-up.js.map +1 -0
  148. package/dist/esm/components/elements/form-warning.js +15 -0
  149. package/dist/esm/components/elements/form-warning.js.map +1 -0
  150. package/dist/esm/components/elements/maybe-full-page.js +50 -0
  151. package/dist/esm/components/elements/maybe-full-page.js.map +1 -0
  152. package/dist/esm/components/elements/separator-with-text.js +17 -0
  153. package/dist/esm/components/elements/separator-with-text.js.map +1 -0
  154. package/dist/esm/components/elements/sidebar-layout.js +102 -0
  155. package/dist/esm/components/elements/sidebar-layout.js.map +1 -0
  156. package/dist/esm/components/elements/ssr-layout-effect.js +23 -0
  157. package/dist/esm/components/elements/ssr-layout-effect.js.map +1 -0
  158. package/dist/esm/components/elements/user-avatar.js +16 -0
  159. package/dist/esm/components/elements/user-avatar.js.map +1 -0
  160. package/dist/esm/components/iframe-preventer.js +28 -0
  161. package/dist/esm/components/iframe-preventer.js.map +1 -0
  162. package/dist/esm/components/link.js +26 -0
  163. package/dist/esm/components/link.js.map +1 -0
  164. package/dist/esm/components/magic-link-sign-in.js +127 -0
  165. package/dist/esm/components/magic-link-sign-in.js.map +1 -0
  166. package/dist/esm/components/message-cards/known-error-message-card.js +37 -0
  167. package/dist/esm/components/message-cards/known-error-message-card.js.map +1 -0
  168. package/dist/esm/components/message-cards/message-card.js +21 -0
  169. package/dist/esm/components/message-cards/message-card.js.map +1 -0
  170. package/dist/esm/components/message-cards/predefined-message-card.js +83 -0
  171. package/dist/esm/components/message-cards/predefined-message-card.js.map +1 -0
  172. package/dist/esm/components/oauth-button-group.js +19 -0
  173. package/dist/esm/components/oauth-button-group.js.map +1 -0
  174. package/dist/esm/components/oauth-button.js +176 -0
  175. package/dist/esm/components/oauth-button.js.map +1 -0
  176. package/dist/esm/components/passkey-button.js +34 -0
  177. package/dist/esm/components/passkey-button.js.map +1 -0
  178. package/dist/esm/components/profile-image-editor.js +126 -0
  179. package/dist/esm/components/profile-image-editor.js.map +1 -0
  180. package/dist/esm/components/selected-team-switcher.js +107 -0
  181. package/dist/esm/components/selected-team-switcher.js.map +1 -0
  182. package/dist/esm/components/team-icon.js +14 -0
  183. package/dist/esm/components/team-icon.js.map +1 -0
  184. package/dist/esm/components/user-button.js +96 -0
  185. package/dist/esm/components/user-button.js.map +1 -0
  186. package/dist/esm/components-page/account-settings.js +1058 -0
  187. package/dist/esm/components-page/account-settings.js.map +1 -0
  188. package/dist/esm/components-page/auth-page.js +99 -0
  189. package/dist/esm/components-page/auth-page.js.map +1 -0
  190. package/dist/esm/components-page/email-verification.js +66 -0
  191. package/dist/esm/components-page/email-verification.js.map +1 -0
  192. package/dist/esm/components-page/error-page.js +73 -0
  193. package/dist/esm/components-page/error-page.js.map +1 -0
  194. package/dist/esm/components-page/forgot-password.js +92 -0
  195. package/dist/esm/components-page/forgot-password.js.map +1 -0
  196. package/dist/esm/components-page/magic-link-callback.js +76 -0
  197. package/dist/esm/components-page/magic-link-callback.js.map +1 -0
  198. package/dist/esm/components-page/oauth-callback.js +51 -0
  199. package/dist/esm/components-page/oauth-callback.js.map +1 -0
  200. package/dist/esm/components-page/password-reset.js +145 -0
  201. package/dist/esm/components-page/password-reset.js.map +1 -0
  202. package/dist/esm/components-page/sign-in.js +19 -0
  203. package/dist/esm/components-page/sign-in.js.map +1 -0
  204. package/dist/esm/components-page/sign-out.js +23 -0
  205. package/dist/esm/components-page/sign-out.js.map +1 -0
  206. package/dist/esm/components-page/sign-up.js +23 -0
  207. package/dist/esm/components-page/sign-up.js.map +1 -0
  208. package/dist/esm/components-page/stack-handler.js +223 -0
  209. package/dist/esm/components-page/stack-handler.js.map +1 -0
  210. package/dist/esm/components-page/team-creation.js +68 -0
  211. package/dist/esm/components-page/team-creation.js.map +1 -0
  212. package/dist/esm/components-page/team-invitation.js +110 -0
  213. package/dist/esm/components-page/team-invitation.js.map +1 -0
  214. package/dist/esm/generated/global-css.js +6 -0
  215. package/dist/esm/generated/global-css.js.map +1 -0
  216. package/dist/esm/generated/quetzal-translations.js +2397 -0
  217. package/dist/esm/generated/quetzal-translations.js.map +1 -0
  218. package/dist/esm/global.d.js +1 -0
  219. package/dist/esm/global.d.js.map +1 -0
  220. package/dist/esm/index.js +46 -0
  221. package/dist/esm/index.js.map +1 -0
  222. package/dist/esm/lib/auth.js +98 -0
  223. package/dist/esm/lib/auth.js.map +1 -0
  224. package/dist/esm/lib/cookie.js +244 -0
  225. package/dist/esm/lib/cookie.js.map +1 -0
  226. package/dist/esm/lib/hooks.js +30 -0
  227. package/dist/esm/lib/hooks.js.map +1 -0
  228. package/dist/esm/lib/stack-app.js +2398 -0
  229. package/dist/esm/lib/stack-app.js.map +1 -0
  230. package/dist/esm/lib/translations.js +23 -0
  231. package/dist/esm/lib/translations.js.map +1 -0
  232. package/dist/esm/providers/stack-provider-client.js +29 -0
  233. package/dist/esm/providers/stack-provider-client.js.map +1 -0
  234. package/dist/esm/providers/stack-provider.js +25 -0
  235. package/dist/esm/providers/stack-provider.js.map +1 -0
  236. package/dist/esm/providers/theme-provider.js +71 -0
  237. package/dist/esm/providers/theme-provider.js.map +1 -0
  238. package/dist/esm/providers/translation-provider-client.js +18 -0
  239. package/dist/esm/providers/translation-provider-client.js.map +1 -0
  240. package/dist/esm/providers/translation-provider.js +18 -0
  241. package/dist/esm/providers/translation-provider.js.map +1 -0
  242. package/dist/esm/utils/browser-script.js +112 -0
  243. package/dist/esm/utils/browser-script.js.map +1 -0
  244. package/dist/esm/utils/constants.js +66 -0
  245. package/dist/esm/utils/constants.js.map +1 -0
  246. package/dist/esm/utils/url.js +30 -0
  247. package/dist/esm/utils/url.js.map +1 -0
  248. package/dist/generated/global-css.d.mts +3 -0
  249. package/dist/generated/global-css.d.ts +3 -0
  250. package/dist/generated/global-css.js +31 -0
  251. package/dist/generated/global-css.js.map +1 -0
  252. package/dist/generated/quetzal-translations.d.mts +4 -0
  253. package/dist/generated/quetzal-translations.d.ts +4 -0
  254. package/dist/generated/quetzal-translations.js +2423 -0
  255. package/dist/generated/quetzal-translations.js.map +1 -0
  256. package/dist/global.d.d.mts +2 -0
  257. package/dist/global.d.d.ts +2 -0
  258. package/dist/global.d.js +2 -0
  259. package/dist/global.d.js.map +1 -0
  260. package/dist/index.d.mts +41 -0
  261. package/dist/index.d.ts +41 -0
  262. package/dist/index.js +103 -0
  263. package/dist/index.js.map +1 -0
  264. package/dist/lib/auth.d.mts +33 -0
  265. package/dist/lib/auth.d.ts +33 -0
  266. package/dist/lib/auth.js +125 -0
  267. package/dist/lib/auth.js.map +1 -0
  268. package/dist/lib/cookie.d.mts +33 -0
  269. package/dist/lib/cookie.d.ts +33 -0
  270. package/dist/lib/cookie.js +291 -0
  271. package/dist/lib/cookie.js.map +1 -0
  272. package/dist/lib/hooks.d.mts +41 -0
  273. package/dist/lib/hooks.d.ts +41 -0
  274. package/dist/lib/hooks.js +56 -0
  275. package/dist/lib/hooks.js.map +1 -0
  276. package/dist/lib/stack-app.d.mts +775 -0
  277. package/dist/lib/stack-app.d.ts +775 -0
  278. package/dist/lib/stack-app.js +2438 -0
  279. package/dist/lib/stack-app.js.map +1 -0
  280. package/dist/lib/translations.d.mts +5 -0
  281. package/dist/lib/translations.d.ts +5 -0
  282. package/dist/lib/translations.js +58 -0
  283. package/dist/lib/translations.js.map +1 -0
  284. package/dist/providers/stack-provider-client.d.mts +27 -0
  285. package/dist/providers/stack-provider-client.d.ts +27 -0
  286. package/dist/providers/stack-provider-client.js +65 -0
  287. package/dist/providers/stack-provider-client.js.map +1 -0
  288. package/dist/providers/stack-provider.d.mts +30 -0
  289. package/dist/providers/stack-provider.d.ts +30 -0
  290. package/dist/providers/stack-provider.js +46 -0
  291. package/dist/providers/stack-provider.js.map +1 -0
  292. package/dist/providers/theme-provider.d.mts +40 -0
  293. package/dist/providers/theme-provider.d.ts +40 -0
  294. package/dist/providers/theme-provider.js +105 -0
  295. package/dist/providers/theme-provider.js.map +1 -0
  296. package/dist/providers/translation-provider-client.d.mts +14 -0
  297. package/dist/providers/translation-provider-client.d.ts +14 -0
  298. package/dist/providers/translation-provider-client.js +43 -0
  299. package/dist/providers/translation-provider-client.js.map +1 -0
  300. package/dist/providers/translation-provider.d.mts +10 -0
  301. package/dist/providers/translation-provider.d.ts +10 -0
  302. package/dist/providers/translation-provider.js +43 -0
  303. package/dist/providers/translation-provider.js.map +1 -0
  304. package/dist/utils/browser-script.d.mts +7 -0
  305. package/dist/utils/browser-script.d.ts +7 -0
  306. package/dist/utils/browser-script.js +137 -0
  307. package/dist/utils/browser-script.js.map +1 -0
  308. package/dist/utils/constants.d.mts +79 -0
  309. package/dist/utils/constants.d.ts +79 -0
  310. package/dist/utils/constants.js +99 -0
  311. package/dist/utils/constants.js.map +1 -0
  312. package/dist/utils/url.d.mts +4 -0
  313. package/dist/utils/url.d.ts +4 -0
  314. package/dist/utils/url.js +56 -0
  315. package/dist/utils/url.js.map +1 -0
  316. package/package.json +96 -0
@@ -0,0 +1,176 @@
1
+ "use client";
2
+ "use client";
3
+
4
+ // src/components/oauth-button.tsx
5
+ import { BrandIcons, Button } from "@stackframe/stack-ui";
6
+ import Color from "color";
7
+ import { useEffect, useId, useState } from "react";
8
+ import { useStackApp } from "..";
9
+ import { useTranslation } from "../lib/translations";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ var iconSize = 22;
12
+ var changeColor = (c, value) => {
13
+ if (c.isLight()) {
14
+ value = -value;
15
+ }
16
+ return c.hsl(c.hue(), c.saturationl(), c.lightness() + value).toString();
17
+ };
18
+ function OAuthButton({
19
+ provider,
20
+ type
21
+ }) {
22
+ const { t } = useTranslation();
23
+ const stackApp = useStackApp();
24
+ const styleId = useId().replaceAll(":", "-");
25
+ const [lastUsed, setLastUsed] = useState(null);
26
+ useEffect(() => {
27
+ setLastUsed(localStorage.getItem("_STACK_AUTH.lastUsed"));
28
+ }, []);
29
+ let style;
30
+ switch (provider) {
31
+ case "google": {
32
+ style = {
33
+ backgroundColor: "#fff",
34
+ textColor: "#000",
35
+ name: "Google",
36
+ border: "1px solid #ddd",
37
+ icon: /* @__PURE__ */ jsx(BrandIcons.Google, { iconSize })
38
+ };
39
+ break;
40
+ }
41
+ case "github": {
42
+ style = {
43
+ backgroundColor: "#111",
44
+ textColor: "#fff",
45
+ border: "1px solid #333",
46
+ name: "GitHub",
47
+ icon: /* @__PURE__ */ jsx(BrandIcons.GitHub, { iconSize })
48
+ };
49
+ break;
50
+ }
51
+ case "facebook": {
52
+ style = {
53
+ backgroundColor: "#1877F2",
54
+ textColor: "#fff",
55
+ name: "Facebook",
56
+ icon: /* @__PURE__ */ jsx(BrandIcons.Facebook, { iconSize })
57
+ };
58
+ break;
59
+ }
60
+ case "microsoft": {
61
+ style = {
62
+ backgroundColor: "#2f2f2f",
63
+ textColor: "#fff",
64
+ name: "Microsoft",
65
+ icon: /* @__PURE__ */ jsx(BrandIcons.Microsoft, { iconSize })
66
+ };
67
+ break;
68
+ }
69
+ case "spotify": {
70
+ style = {
71
+ backgroundColor: "#1DB954",
72
+ textColor: "#fff",
73
+ name: "Spotify",
74
+ icon: /* @__PURE__ */ jsx(BrandIcons.Spotify, { iconSize })
75
+ };
76
+ break;
77
+ }
78
+ case "discord": {
79
+ style = {
80
+ backgroundColor: "#5865F2",
81
+ textColor: "#fff",
82
+ name: "Discord",
83
+ icon: /* @__PURE__ */ jsx(BrandIcons.Discord, { iconSize })
84
+ };
85
+ break;
86
+ }
87
+ case "gitlab": {
88
+ style = {
89
+ backgroundColor: "#111",
90
+ textColor: "#fff",
91
+ border: "1px solid #333",
92
+ name: "Gitlab",
93
+ icon: /* @__PURE__ */ jsx(BrandIcons.Gitlab, { iconSize })
94
+ };
95
+ break;
96
+ }
97
+ case "apple": {
98
+ style = {
99
+ backgroundColor: "#000",
100
+ textColor: "#fff",
101
+ border: "1px solid #333",
102
+ name: "Apple",
103
+ icon: /* @__PURE__ */ jsx(BrandIcons.Apple, { iconSize })
104
+ };
105
+ break;
106
+ }
107
+ case "bitbucket": {
108
+ style = {
109
+ backgroundColor: "#fff",
110
+ textColor: "#000",
111
+ border: "1px solid #ddd",
112
+ name: "Bitbucket",
113
+ icon: /* @__PURE__ */ jsx(BrandIcons.Bitbucket, { iconSize })
114
+ };
115
+ break;
116
+ }
117
+ case "linkedin": {
118
+ style = {
119
+ backgroundColor: "#0073b1",
120
+ textColor: "#fff",
121
+ name: "LinkedIn",
122
+ icon: /* @__PURE__ */ jsx(BrandIcons.LinkedIn, { iconSize })
123
+ };
124
+ break;
125
+ }
126
+ case "x": {
127
+ style = {
128
+ backgroundColor: "#000",
129
+ textColor: "#fff",
130
+ name: "X",
131
+ icon: /* @__PURE__ */ jsx(BrandIcons.X, { iconSize })
132
+ };
133
+ break;
134
+ }
135
+ default: {
136
+ style = {
137
+ name: provider,
138
+ icon: null
139
+ };
140
+ }
141
+ }
142
+ const styleSheet = `
143
+ .stack-oauth-button-${styleId} {
144
+ background-color: ${style.backgroundColor} !important;
145
+ color: ${style.textColor} !important;
146
+ border: ${style.border} !important;
147
+ }
148
+ .stack-oauth-button-${styleId}:hover {
149
+ background-color: ${changeColor(Color(style.backgroundColor), 10)} !important;
150
+ }
151
+ `;
152
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
153
+ /* @__PURE__ */ jsx("style", { children: styleSheet }),
154
+ /* @__PURE__ */ jsxs(
155
+ Button,
156
+ {
157
+ onClick: async () => {
158
+ localStorage.setItem("_STACK_AUTH.lastUsed", provider);
159
+ await stackApp.signInWithOAuth(provider);
160
+ },
161
+ className: `stack-oauth-button-${styleId} stack-scope relative`,
162
+ children: [
163
+ lastUsed === provider && /* @__PURE__ */ jsx("span", { className: "absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md", children: "last" }),
164
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center w-full gap-4", children: [
165
+ style.icon,
166
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: type === "sign-up" ? t("Sign up with {provider}", { provider: style.name }) : t("Sign in with {provider}", { provider: style.name }) })
167
+ ] })
168
+ ]
169
+ }
170
+ )
171
+ ] });
172
+ }
173
+ export {
174
+ OAuthButton
175
+ };
176
+ //# sourceMappingURL=oauth-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/oauth-button.tsx"],"sourcesContent":["'use client';\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\n\nimport { BrandIcons, Button } from '@stackframe/stack-ui';\nimport Color from 'color';\nimport { useEffect, useId, useState } from 'react';\nimport { useStackApp } from '..';\nimport { useTranslation } from '../lib/translations';\n\nconst iconSize = 22;\n\nconst changeColor = (c: Color, value: number) => {\n if (c.isLight()) {\n value = -value;\n }\n return c.hsl(c.hue(), c.saturationl(), c.lightness() + value).toString();\n};\n\nexport function OAuthButton({\n provider,\n type,\n}: {\n provider: string,\n type: 'sign-in' | 'sign-up',\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const styleId = useId().replaceAll(':', '-');\n\n const [lastUsed, setLastUsed] = useState<string | null>(null);\n useEffect(() => {\n setLastUsed(localStorage.getItem('_STACK_AUTH.lastUsed'));\n }, []);\n\n let style : {\n backgroundColor?: string,\n textColor?: string,\n name: string,\n icon: JSX.Element | null,\n border?: string,\n };\n switch (provider) {\n case 'google': {\n style = {\n backgroundColor: '#fff',\n textColor: '#000',\n name: 'Google',\n border: '1px solid #ddd',\n icon: <BrandIcons.Google iconSize={iconSize} />,\n };\n break;\n }\n case 'github': {\n style = {\n backgroundColor: '#111',\n textColor: '#fff',\n border: '1px solid #333',\n name: 'GitHub',\n icon: <BrandIcons.GitHub iconSize={iconSize} />,\n };\n break;\n }\n case 'facebook': {\n style = {\n backgroundColor: '#1877F2',\n textColor: '#fff',\n name: 'Facebook',\n icon: <BrandIcons.Facebook iconSize={iconSize} />,\n };\n break;\n }\n case 'microsoft': {\n style = {\n backgroundColor: '#2f2f2f',\n textColor: '#fff',\n name: 'Microsoft',\n icon: <BrandIcons.Microsoft iconSize={iconSize} />,\n };\n break;\n }\n case 'spotify': {\n style = {\n backgroundColor: '#1DB954',\n textColor: '#fff',\n name: 'Spotify',\n icon: <BrandIcons.Spotify iconSize={iconSize} />,\n };\n break;\n }\n case 'discord': {\n style = {\n backgroundColor: '#5865F2',\n textColor: '#fff',\n name: 'Discord',\n icon: <BrandIcons.Discord iconSize={iconSize} />,\n };\n break;\n }\n case 'gitlab': {\n style = {\n backgroundColor: \"#111\",\n textColor: \"#fff\",\n border: \"1px solid #333\",\n name: \"Gitlab\",\n icon: <BrandIcons.Gitlab iconSize={iconSize} />,\n };\n break;\n }\n case 'apple': {\n style = {\n backgroundColor: \"#000\",\n textColor: \"#fff\",\n border: \"1px solid #333\",\n name: \"Apple\",\n icon: <BrandIcons.Apple iconSize={iconSize} />,\n };\n break;\n }\n case \"bitbucket\": {\n style = {\n backgroundColor: \"#fff\",\n textColor: \"#000\",\n border: \"1px solid #ddd\",\n name: \"Bitbucket\",\n icon: <BrandIcons.Bitbucket iconSize={iconSize} />,\n };\n break;\n }\n case 'linkedin': {\n style = {\n backgroundColor: \"#0073b1\",\n textColor: \"#fff\",\n name: \"LinkedIn\",\n icon: <BrandIcons.LinkedIn iconSize={iconSize} />,\n };\n break;\n }\n case 'x': {\n style = {\n backgroundColor: \"#000\",\n textColor: \"#fff\",\n name: \"X\",\n icon: <BrandIcons.X iconSize={iconSize} />,\n };\n break;\n }\n default: {\n style = {\n name: provider,\n icon: null,\n };\n }\n }\n\n const styleSheet = `\n .stack-oauth-button-${styleId} {\n background-color: ${style.backgroundColor} !important;\n color: ${style.textColor} !important;\n border: ${style.border} !important;\n }\n .stack-oauth-button-${styleId}:hover {\n background-color: ${changeColor(Color(style.backgroundColor), 10)} !important;\n }\n `;\n\n return (\n <>\n <style>{styleSheet}</style>\n <Button\n onClick={async () => {\n localStorage.setItem('_STACK_AUTH.lastUsed', provider);\n await stackApp.signInWithOAuth(provider);\n }}\n className={`stack-oauth-button-${styleId} stack-scope relative`}\n >\n {lastUsed === provider && (\n <span className=\"absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md\">\n last\n </span>\n )}\n <div className='flex items-center w-full gap-4'>\n {style.icon}\n <span className='flex-1'>\n {type === 'sign-up' ?\n t('Sign up with {provider}', { provider: style.name }) :\n t('Sign in with {provider}', { provider: style.name })\n }\n </span>\n </div>\n </Button>\n </>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ "use client";
3
+
4
+ // src/components/passkey-button.tsx
5
+ import { Button } from "@stackframe/stack-ui";
6
+ import { useId } from "react";
7
+ import { useStackApp } from "..";
8
+ import { useTranslation } from "../lib/translations";
9
+ import { KeyRound } from "lucide-react";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ function PasskeyButton({
12
+ type
13
+ }) {
14
+ const { t } = useTranslation();
15
+ const stackApp = useStackApp();
16
+ const styleId = useId().replaceAll(":", "-");
17
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
18
+ Button,
19
+ {
20
+ onClick: async () => {
21
+ await stackApp.signInWithPasskey();
22
+ },
23
+ className: `stack-oauth-button-${styleId} stack-scope`,
24
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center w-full gap-4", children: [
25
+ /* @__PURE__ */ jsx(KeyRound, {}),
26
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: type === "sign-up" ? t("Sign up with Passkey") : t("Sign in with Passkey") })
27
+ ] })
28
+ }
29
+ ) });
30
+ }
31
+ export {
32
+ PasskeyButton
33
+ };
34
+ //# sourceMappingURL=passkey-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/passkey-button.tsx"],"sourcesContent":["'use client';\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\n\nimport { Button } from '@stackframe/stack-ui';\nimport { useId } from 'react';\nimport { useStackApp } from '..';\nimport { useTranslation } from '../lib/translations';\nimport { KeyRound } from 'lucide-react';\n\n\nexport function PasskeyButton({\n type,\n}: {\n type: 'sign-in' | 'sign-up',\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const styleId = useId().replaceAll(':', '-');\n\n\n return (\n <>\n <Button\n onClick={async () => { await stackApp.signInWithPasskey(); }}\n className={`stack-oauth-button-${styleId} stack-scope`}\n >\n <div className='flex items-center w-full gap-4'>\n <KeyRound />\n <span className='flex-1'>\n {type === 'sign-up' ?\n t('Sign up with Passkey') :\n t('Sign in with Passkey')\n }\n </span>\n </div>\n </Button>\n </>\n );\n}\n"],"mappings":";;;AAOA,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AAcrB,mBAMM,KADF,YALJ;AAXG,SAAS,cAAc;AAAA,EAC5B;AACF,GAEG;AACD,QAAM,EAAE,EAAE,IAAI,eAAe;AAC7B,QAAM,WAAW,YAAY;AAC7B,QAAM,UAAU,MAAM,EAAE,WAAW,KAAK,GAAG;AAG3C,SACE,gCACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,YAAY;AAAE,cAAM,SAAS,kBAAkB;AAAA,MAAG;AAAA,MAC3D,WAAW,sBAAsB,OAAO;AAAA,MAExC,+BAAC,SAAI,WAAU,kCACb;AAAA,4BAAC,YAAS;AAAA,QACV,oBAAC,UAAK,WAAU,UACb,mBAAS,YACR,EAAE,sBAAsB,IACxB,EAAE,sBAAsB,GAE5B;AAAA,SACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
@@ -0,0 +1,126 @@
1
+ // src/components/profile-image-editor.tsx
2
+ import { fileToBase64 } from "@stackframe/stack-shared/dist/utils/base64";
3
+ import { Button, Slider, Typography } from "@stackframe/stack-ui";
4
+ import imageCompression from "browser-image-compression";
5
+ import { Upload } from "lucide-react";
6
+ import { useRef, useState } from "react";
7
+ import AvatarEditor from "react-avatar-editor";
8
+ import { useTranslation } from "../lib/translations";
9
+ import { UserAvatar } from "./elements/user-avatar";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ async function checkImageUrl(url) {
12
+ try {
13
+ const res = await fetch(url, { method: "HEAD" });
14
+ const buff = await res.blob();
15
+ return buff.type.startsWith("image/");
16
+ } catch (e) {
17
+ return false;
18
+ }
19
+ }
20
+ function ProfileImageEditor(props) {
21
+ const { t } = useTranslation();
22
+ const cropRef = useRef(null);
23
+ const [slideValue, setSlideValue] = useState(1);
24
+ const [rawUrl, setRawUrl] = useState(null);
25
+ const [error, setError] = useState(null);
26
+ function reset() {
27
+ setSlideValue(1);
28
+ setRawUrl(null);
29
+ setError(null);
30
+ }
31
+ function upload() {
32
+ const input = document.createElement("input");
33
+ input.type = "file";
34
+ input.onchange = (e) => {
35
+ const file = e.target.files?.[0];
36
+ if (!file) return;
37
+ fileToBase64(file).then(async (rawUrl2) => {
38
+ if (await checkImageUrl(rawUrl2)) {
39
+ setRawUrl(rawUrl2);
40
+ setError(null);
41
+ } else {
42
+ setError(t("Invalid image"));
43
+ }
44
+ }).then(() => input.remove()).catch(console.error);
45
+ };
46
+ input.click();
47
+ }
48
+ if (!rawUrl) {
49
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
50
+ /* @__PURE__ */ jsxs("div", { className: "cursor-pointer relative", onClick: upload, children: [
51
+ /* @__PURE__ */ jsx(
52
+ UserAvatar,
53
+ {
54
+ size: 60,
55
+ user: props.user,
56
+ border: true
57
+ }
58
+ ),
59
+ /* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 h-[60px] w-[60px] bg-gray-500/20 backdrop-blur-sm items-center justify-center rounded-full flex opacity-0 hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsx("div", { className: "bg-background p-2 rounded-full", children: /* @__PURE__ */ jsx(Upload, { className: "h-5 w-5" }) }) })
60
+ ] }),
61
+ error && /* @__PURE__ */ jsx(Typography, { variant: "destructive", type: "label", children: error })
62
+ ] });
63
+ }
64
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
65
+ /* @__PURE__ */ jsx(
66
+ AvatarEditor,
67
+ {
68
+ ref: cropRef,
69
+ image: rawUrl || props.user.profileImageUrl || "",
70
+ borderRadius: 1e3,
71
+ color: [0, 0, 0, 0.72],
72
+ scale: slideValue,
73
+ rotate: 0,
74
+ border: 20,
75
+ className: "border"
76
+ }
77
+ ),
78
+ /* @__PURE__ */ jsx(
79
+ Slider,
80
+ {
81
+ min: 1,
82
+ max: 5,
83
+ step: 0.1,
84
+ defaultValue: [slideValue],
85
+ value: [slideValue],
86
+ onValueChange: (v) => setSlideValue(v[0])
87
+ }
88
+ ),
89
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-2", children: [
90
+ /* @__PURE__ */ jsx(
91
+ Button,
92
+ {
93
+ onClick: async () => {
94
+ if (cropRef.current && rawUrl) {
95
+ const croppedUrl = cropRef.current.getImage().toDataURL("image/jpeg");
96
+ const compressedFile = await imageCompression(
97
+ await imageCompression.getFilefromDataUrl(croppedUrl, "profile-image"),
98
+ {
99
+ maxSizeMB: 0.1,
100
+ fileType: "image/jpeg"
101
+ }
102
+ );
103
+ const compressedUrl = await imageCompression.getDataUrlFromFile(compressedFile);
104
+ await props.onProfileImageUrlChange(compressedUrl);
105
+ reset();
106
+ }
107
+ },
108
+ children: t("Save")
109
+ }
110
+ ),
111
+ /* @__PURE__ */ jsx(
112
+ Button,
113
+ {
114
+ variant: "secondary",
115
+ onClick: reset,
116
+ children: t("Cancel")
117
+ }
118
+ )
119
+ ] })
120
+ ] });
121
+ }
122
+ export {
123
+ ProfileImageEditor,
124
+ checkImageUrl
125
+ };
126
+ //# sourceMappingURL=profile-image-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/profile-image-editor.tsx"],"sourcesContent":["//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { fileToBase64 } from '@stackframe/stack-shared/dist/utils/base64';\nimport { Button, Slider, Typography } from '@stackframe/stack-ui';\nimport imageCompression from 'browser-image-compression';\nimport { Upload } from 'lucide-react';\nimport { ComponentProps, useRef, useState } from 'react';\nimport AvatarEditor from 'react-avatar-editor';\nimport { useTranslation } from '../lib/translations';\nimport { UserAvatar } from './elements/user-avatar';\n\nexport async function checkImageUrl(url: string){\n try {\n const res = await fetch(url, { method: 'HEAD' });\n const buff = await res.blob();\n return buff.type.startsWith('image/');\n } catch (e) {\n return false;\n }\n}\n\nexport function ProfileImageEditor(props: {\n user: NonNullable<ComponentProps<typeof UserAvatar>['user']>,\n onProfileImageUrlChange: (profileImageUrl: string | null) => void | Promise<void>,\n}) {\n const { t } = useTranslation();\n const cropRef = useRef<AvatarEditor>(null);\n const [slideValue, setSlideValue] = useState(1);\n const [rawUrl, setRawUrl] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n function reset() {\n setSlideValue(1);\n setRawUrl(null);\n setError(null);\n }\n\n function upload() {\n const input = document.createElement('input');\n input.type = 'file';\n input.onchange = (e) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (!file) return;\n fileToBase64(file)\n .then(async (rawUrl) => {\n if (await checkImageUrl(rawUrl)) {\n setRawUrl(rawUrl);\n setError(null);\n } else {\n setError(t('Invalid image'));\n }\n })\n .then(() => input.remove())\n .catch(console.error);\n };\n input.click();\n }\n\n if (!rawUrl) {\n return <div className='flex flex-col'>\n <div className='cursor-pointer relative' onClick={upload}>\n <UserAvatar\n size={60}\n user={props.user}\n border\n />\n <div className='absolute top-0 left-0 h-[60px] w-[60px] bg-gray-500/20 backdrop-blur-sm items-center justify-center rounded-full flex opacity-0 hover:opacity-100 transition-opacity'>\n <div className='bg-background p-2 rounded-full'>\n <Upload className='h-5 w-5' />\n </div>\n </div>\n </div>\n {error && <Typography variant='destructive' type='label'>{error}</Typography>}\n </div>;\n }\n\n return (\n <div className='flex flex-col items-center gap-4'>\n <AvatarEditor\n ref={cropRef}\n image={rawUrl || props.user.profileImageUrl || \"\"}\n borderRadius={1000}\n color={[0, 0, 0, 0.72]}\n scale={slideValue}\n rotate={0}\n border={20}\n className='border'\n />\n <Slider\n min={1}\n max={5}\n step={0.1}\n defaultValue={[slideValue]}\n value={[slideValue]}\n onValueChange={(v) => setSlideValue(v[0])}\n />\n\n <div className='flex flex-row gap-2'>\n <Button\n onClick={async () => {\n if (cropRef.current && rawUrl) {\n const croppedUrl = cropRef.current.getImage().toDataURL('image/jpeg');\n const compressedFile = await imageCompression(\n await imageCompression.getFilefromDataUrl(croppedUrl, 'profile-image'),\n {\n maxSizeMB: 0.1,\n fileType: \"image/jpeg\",\n }\n );\n const compressedUrl = await imageCompression.getDataUrlFromFile(compressedFile);\n await props.onProfileImageUrlChange(compressedUrl);\n reset();\n }\n }}\n >\n {t('Save')}\n </Button>\n <Button\n variant=\"secondary\"\n onClick={reset}\n >\n {t('Cancel')}\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["rawUrl"]}
@@ -0,0 +1,107 @@
1
+ "use client";
2
+ "use client";
3
+
4
+ // src/components/selected-team-switcher.tsx
5
+ import { runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
6
+ import {
7
+ Button,
8
+ Select,
9
+ SelectContent,
10
+ SelectGroup,
11
+ SelectItem,
12
+ SelectLabel,
13
+ SelectSeparator,
14
+ SelectTrigger,
15
+ SelectValue,
16
+ Skeleton,
17
+ Typography
18
+ } from "@stackframe/stack-ui";
19
+ import { PlusCircle, Settings } from "lucide-react";
20
+ import { Suspense, useEffect, useMemo } from "react";
21
+ import { useStackApp, useUser } from "..";
22
+ import { useTranslation } from "../lib/translations";
23
+ import { TeamIcon } from "./team-icon";
24
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
25
+ function SelectedTeamSwitcher(props) {
26
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Fallback, {}), children: /* @__PURE__ */ jsx(Inner, { ...props }) });
27
+ }
28
+ function Fallback() {
29
+ return /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-full max-w-64 stack-scope" });
30
+ }
31
+ function Inner(props) {
32
+ const { t } = useTranslation();
33
+ const app = useStackApp();
34
+ const user = useUser();
35
+ const project = app.useProject();
36
+ const navigate = app.useNavigate();
37
+ const selectedTeam = user?.selectedTeam || props.selectedTeam;
38
+ const rawTeams = user?.useTeams();
39
+ const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);
40
+ useEffect(() => {
41
+ if (!props.noUpdateSelectedTeam && props.selectedTeam) {
42
+ runAsynchronouslyWithAlert(user?.setSelectedTeam(props.selectedTeam));
43
+ }
44
+ }, [props.noUpdateSelectedTeam, props.selectedTeam]);
45
+ return /* @__PURE__ */ jsxs(
46
+ Select,
47
+ {
48
+ value: selectedTeam?.id,
49
+ onValueChange: (value) => {
50
+ runAsynchronouslyWithAlert(async () => {
51
+ const team = teams?.find((team2) => team2.id === value);
52
+ if (!team) {
53
+ throw new Error("Team not found, this should not happen");
54
+ }
55
+ if (!props.noUpdateSelectedTeam) {
56
+ await user?.setSelectedTeam(team);
57
+ }
58
+ if (props.urlMap) {
59
+ navigate(props.urlMap(team));
60
+ }
61
+ });
62
+ },
63
+ children: [
64
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "stack-scope max-w-64", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select team" }) }),
65
+ /* @__PURE__ */ jsxs(SelectContent, { className: "stack-scope", children: [
66
+ user?.selectedTeam ? /* @__PURE__ */ jsxs(SelectGroup, { children: [
67
+ /* @__PURE__ */ jsx(SelectLabel, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
68
+ /* @__PURE__ */ jsx("span", { children: t("Current team") }),
69
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", onClick: () => navigate(`${app.urls.accountSettings}#team-${user.selectedTeam?.id}`), children: /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }) })
70
+ ] }) }),
71
+ /* @__PURE__ */ jsx(SelectItem, { value: user.selectedTeam.id, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
72
+ /* @__PURE__ */ jsx(TeamIcon, { team: user.selectedTeam }),
73
+ /* @__PURE__ */ jsx(Typography, { className: "max-w-40 truncate", children: user.selectedTeam.displayName })
74
+ ] }) })
75
+ ] }) : void 0,
76
+ teams?.length ? /* @__PURE__ */ jsxs(SelectGroup, { children: [
77
+ /* @__PURE__ */ jsx(SelectLabel, { children: t("Other teams") }),
78
+ teams.filter((team) => team.id !== user?.selectedTeam?.id).map((team) => /* @__PURE__ */ jsx(SelectItem, { value: team.id, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
79
+ /* @__PURE__ */ jsx(TeamIcon, { team }),
80
+ /* @__PURE__ */ jsx(Typography, { className: "max-w-64 truncate", children: team.displayName })
81
+ ] }) }, team.id))
82
+ ] }) : /* @__PURE__ */ jsx(SelectGroup, { children: /* @__PURE__ */ jsx(SelectLabel, { children: t("No teams yet") }) }),
83
+ project.config.clientTeamCreationEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
84
+ /* @__PURE__ */ jsx(SelectSeparator, {}),
85
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
86
+ Button,
87
+ {
88
+ onClick: () => navigate(`${app.urls.accountSettings}#team-creation`),
89
+ className: "w-full",
90
+ variant: "ghost",
91
+ children: [
92
+ /* @__PURE__ */ jsx(PlusCircle, { className: "mr-2 h-4 w-4" }),
93
+ " ",
94
+ t("Create a team")
95
+ ]
96
+ }
97
+ ) })
98
+ ] })
99
+ ] })
100
+ ]
101
+ }
102
+ );
103
+ }
104
+ export {
105
+ SelectedTeamSwitcher
106
+ };
107
+ //# sourceMappingURL=selected-team-switcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/selected-team-switcher.tsx"],"sourcesContent":["'use client';\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport {\n Button,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Typography\n} from \"@stackframe/stack-ui\";\nimport { PlusCircle, Settings } from \"lucide-react\";\nimport { Suspense, useEffect, useMemo } from \"react\";\nimport { Team, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { TeamIcon } from \"./team-icon\";\n\ntype SelectedTeamSwitcherProps = {\n urlMap?: (team: Team) => string,\n selectedTeam?: Team,\n noUpdateSelectedTeam?: boolean,\n};\n\nexport function SelectedTeamSwitcher(props: SelectedTeamSwitcherProps) {\n return <Suspense fallback={<Fallback />}>\n <Inner {...props} />\n </Suspense>;\n}\n\nfunction Fallback() {\n return <Skeleton className=\"h-9 w-full max-w-64 stack-scope\" />;\n}\n\nfunction Inner(props: SelectedTeamSwitcherProps) {\n const { t } = useTranslation();\n const app = useStackApp();\n const user = useUser();\n const project = app.useProject();\n const navigate = app.useNavigate();\n const selectedTeam = user?.selectedTeam || props.selectedTeam;\n const rawTeams = user?.useTeams();\n const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);\n\n useEffect(() => {\n if (!props.noUpdateSelectedTeam && props.selectedTeam) {\n runAsynchronouslyWithAlert(user?.setSelectedTeam(props.selectedTeam));\n }\n }, [props.noUpdateSelectedTeam, props.selectedTeam]);\n\n return (\n <Select\n value={selectedTeam?.id}\n onValueChange={(value) => {\n runAsynchronouslyWithAlert(async () => {\n const team = teams?.find(team => team.id === value);\n if (!team) {\n throw new Error('Team not found, this should not happen');\n }\n\n if (!props.noUpdateSelectedTeam) {\n await user?.setSelectedTeam(team);\n }\n if (props.urlMap) {\n navigate(props.urlMap(team));\n }\n });\n }}\n >\n <SelectTrigger className=\"stack-scope max-w-64\">\n <SelectValue placeholder=\"Select team\"/>\n </SelectTrigger>\n <SelectContent className=\"stack-scope\">\n {user?.selectedTeam ? <SelectGroup>\n <SelectLabel>\n <div className=\"flex items-center justify-between\">\n <span>\n {t('Current team')}\n </span>\n <Button variant='ghost' size='icon' className=\"h-6 w-6\" onClick={() => navigate(`${app.urls.accountSettings}#team-${user.selectedTeam?.id}`)}>\n <Settings className=\"h-4 w-4\"/>\n </Button>\n </div>\n </SelectLabel>\n <SelectItem value={user.selectedTeam.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={user.selectedTeam} />\n <Typography className=\"max-w-40 truncate\">{user.selectedTeam.displayName}</Typography>\n </div>\n </SelectItem>\n </SelectGroup> : undefined}\n\n {teams?.length ?\n <SelectGroup>\n <SelectLabel>{t('Other teams')}</SelectLabel>\n {teams.filter(team => team.id !== user?.selectedTeam?.id)\n .map(team => (\n <SelectItem value={team.id} key={team.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={team} />\n <Typography className=\"max-w-64 truncate\">{team.displayName}</Typography>\n </div>\n </SelectItem>\n ))}\n </SelectGroup> :\n <SelectGroup>\n <SelectLabel>{t('No teams yet')}</SelectLabel>\n </SelectGroup>}\n\n {project.config.clientTeamCreationEnabled && <>\n <SelectSeparator/>\n <div>\n <Button\n onClick={() => navigate(`${app.urls.accountSettings}#team-creation`)}\n className=\"w-full\"\n variant='ghost'\n >\n <PlusCircle className=\"mr-2 h-4 w-4\"/> {t('Create a team')}\n </Button>\n </div>\n </>}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":"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","names":["team"]}
@@ -0,0 +1,14 @@
1
+ // src/components/team-icon.tsx
2
+ import { Avatar, AvatarImage, Typography } from "@stackframe/stack-ui";
3
+ import { jsx } from "react/jsx-runtime";
4
+ function TeamIcon(props) {
5
+ if (props.team.profileImageUrl) {
6
+ return /* @__PURE__ */ jsx(Avatar, { className: "min-w-6 min-h-6 max-w-6 max-h-6 rounded", children: /* @__PURE__ */ jsx(AvatarImage, { src: props.team.profileImageUrl, alt: props.team.displayName }) });
7
+ } else {
8
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-w-6 min-h-6 max-w-6 max-h-6 rounded bg-zinc-200", children: /* @__PURE__ */ jsx(Typography, { className: "text-zinc-800 dark:text-zinc-800", children: props.team.displayName.slice(0, 1).toUpperCase() }) });
9
+ }
10
+ }
11
+ export {
12
+ TeamIcon
13
+ };
14
+ //# sourceMappingURL=team-icon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/team-icon.tsx"],"sourcesContent":["//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { Avatar, AvatarImage, Typography } from \"@stackframe/stack-ui\";\nimport { Team } from \"..\";\n\nexport function TeamIcon(props: { team: Team }) {\n if (props.team.profileImageUrl) {\n return (\n <Avatar className=\"min-w-6 min-h-6 max-w-6 max-h-6 rounded\">\n <AvatarImage src={props.team.profileImageUrl} alt={props.team.displayName} />\n </Avatar>\n );\n } else {\n return (\n <div className=\"flex items-center justify-center min-w-6 min-h-6 max-w-6 max-h-6 rounded bg-zinc-200\">\n <Typography className=\"text-zinc-800 dark:text-zinc-800\">{props.team.displayName.slice(0, 1).toUpperCase()}</Typography>\n </div>\n );\n }\n}\n"],"mappings":";AAIA,SAAS,QAAQ,aAAa,kBAAkB;AAOxC;AAJD,SAAS,SAAS,OAAuB;AAC9C,MAAI,MAAM,KAAK,iBAAiB;AAC9B,WACE,oBAAC,UAAO,WAAU,2CAChB,8BAAC,eAAY,KAAK,MAAM,KAAK,iBAAiB,KAAK,MAAM,KAAK,aAAa,GAC7E;AAAA,EAEJ,OAAO;AACL,WACE,oBAAC,SAAI,WAAU,wFACb,8BAAC,cAAW,WAAU,oCAAoC,gBAAM,KAAK,YAAY,MAAM,GAAG,CAAC,EAAE,YAAY,GAAE,GAC7G;AAAA,EAEJ;AACF;","names":[]}
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ "use client";
3
+
4
+ // src/components/user-button.tsx
5
+ import { runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
6
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Skeleton, Typography } from "@stackframe/stack-ui";
7
+ import { CircleUser, LogIn, LogOut, SunMoon, UserPlus } from "lucide-react";
8
+ import { Suspense } from "react";
9
+ import { useStackApp, useUser } from "..";
10
+ import { useTranslation } from "../lib/translations";
11
+ import { UserAvatar } from "./elements/user-avatar";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ function Item(props) {
14
+ return /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: () => runAsynchronouslyWithAlert(props.onClick), children: /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
15
+ props.icon,
16
+ /* @__PURE__ */ jsx(Typography, { children: props.text })
17
+ ] }) });
18
+ }
19
+ function UserButton(props) {
20
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Skeleton, { className: "h-[34px] w-[34px] rounded-full stack-scope" }), children: /* @__PURE__ */ jsx(UserButtonInner, { ...props }) });
21
+ }
22
+ function UserButtonInner(props) {
23
+ const user = useUser();
24
+ return /* @__PURE__ */ jsx(UserButtonInnerInner, { ...props, user });
25
+ }
26
+ function UserButtonInnerInner(props) {
27
+ const { t } = useTranslation();
28
+ const user = props.user;
29
+ const app = useStackApp();
30
+ const iconProps = { size: 20, className: "h-4 w-4" };
31
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
32
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { className: "outline-none stack-scope", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
33
+ /* @__PURE__ */ jsx(UserAvatar, { user }),
34
+ user && props.showUserInfo && /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center text-left", children: [
35
+ /* @__PURE__ */ jsx(Typography, { className: "max-w-40 truncate", children: user.displayName }),
36
+ /* @__PURE__ */ jsx(Typography, { className: "max-w-40 truncate", variant: "secondary", type: "label", children: user.primaryEmail })
37
+ ] })
38
+ ] }) }),
39
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { className: "stack-scope", children: [
40
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
41
+ /* @__PURE__ */ jsx(UserAvatar, { user }),
42
+ /* @__PURE__ */ jsxs("div", { children: [
43
+ user && /* @__PURE__ */ jsx(Typography, { className: "max-w-40 truncate", children: user.displayName }),
44
+ user && /* @__PURE__ */ jsx(Typography, { className: "max-w-40 truncate", variant: "secondary", type: "label", children: user.primaryEmail }),
45
+ !user && /* @__PURE__ */ jsx(Typography, { children: t("Not signed in") })
46
+ ] })
47
+ ] }) }),
48
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
49
+ user && /* @__PURE__ */ jsx(
50
+ Item,
51
+ {
52
+ text: t("Account settings"),
53
+ onClick: async () => await app.redirectToAccountSettings(),
54
+ icon: /* @__PURE__ */ jsx(CircleUser, { ...iconProps })
55
+ }
56
+ ),
57
+ !user && /* @__PURE__ */ jsx(
58
+ Item,
59
+ {
60
+ text: t("Sign in"),
61
+ onClick: async () => await app.redirectToSignIn(),
62
+ icon: /* @__PURE__ */ jsx(LogIn, { ...iconProps })
63
+ }
64
+ ),
65
+ !user && /* @__PURE__ */ jsx(
66
+ Item,
67
+ {
68
+ text: t("Sign up"),
69
+ onClick: async () => await app.redirectToSignUp(),
70
+ icon: /* @__PURE__ */ jsx(UserPlus, { ...iconProps })
71
+ }
72
+ ),
73
+ user && props.extraItems && props.extraItems.map((item, index) => /* @__PURE__ */ jsx(Item, { ...item }, index)),
74
+ props.colorModeToggle && /* @__PURE__ */ jsx(
75
+ Item,
76
+ {
77
+ text: t("Toggle theme"),
78
+ onClick: props.colorModeToggle,
79
+ icon: /* @__PURE__ */ jsx(SunMoon, { ...iconProps })
80
+ }
81
+ ),
82
+ user && /* @__PURE__ */ jsx(
83
+ Item,
84
+ {
85
+ text: t("Sign out"),
86
+ onClick: () => user.signOut(),
87
+ icon: /* @__PURE__ */ jsx(LogOut, { ...iconProps })
88
+ }
89
+ )
90
+ ] })
91
+ ] });
92
+ }
93
+ export {
94
+ UserButton
95
+ };
96
+ //# sourceMappingURL=user-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/user-button.tsx"],"sourcesContent":["'use client';\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\n\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Skeleton, Typography } from \"@stackframe/stack-ui\";\nimport { CircleUser, LogIn, LogOut, SunMoon, UserPlus } from \"lucide-react\";\nimport React, { Suspense } from \"react\";\nimport { CurrentUser, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { UserAvatar } from \"./elements/user-avatar\";\n\nfunction Item(props: { text: string, icon: React.ReactNode, onClick: () => void | Promise<void> }) {\n return (\n <DropdownMenuItem onClick={() => runAsynchronouslyWithAlert(props.onClick)}>\n <div className=\"flex gap-2 items-center\">\n {props.icon}\n <Typography>{props.text}</Typography>\n </div>\n </DropdownMenuItem>\n );\n}\n\ntype UserButtonProps = {\n showUserInfo?: boolean,\n colorModeToggle?: () => void | Promise<void>,\n extraItems?: {\n text: string,\n icon: React.ReactNode,\n onClick: () => void | Promise<void>,\n }[],\n};\n\nexport function UserButton(props: UserButtonProps) {\n return (\n <Suspense fallback={<Skeleton className=\"h-[34px] w-[34px] rounded-full stack-scope\" />}>\n <UserButtonInner {...props} />\n </Suspense>\n );\n}\n\nfunction UserButtonInner(props: UserButtonProps) {\n const user = useUser();\n return <UserButtonInnerInner {...props} user={user} />;\n}\n\n\nfunction UserButtonInnerInner(props: UserButtonProps & { user: CurrentUser | null }) {\n const { t } = useTranslation();\n const user = props.user;\n const app = useStackApp();\n\n const iconProps = { size: 20, className: 'h-4 w-4' };\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger className=\"outline-none stack-scope\">\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n {user && props.showUserInfo &&\n <div className=\"flex flex-col justify-center text-left\">\n <Typography className=\"max-w-40 truncate\">{user.displayName}</Typography>\n <Typography className=\"max-w-40 truncate\" variant=\"secondary\" type='label'>{user.primaryEmail}</Typography>\n </div>\n }\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"stack-scope\">\n <DropdownMenuLabel>\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n <div>\n {user && <Typography className=\"max-w-40 truncate\">{user.displayName}</Typography>}\n {user && <Typography className=\"max-w-40 truncate\" variant=\"secondary\" type='label'>{user.primaryEmail}</Typography>}\n {!user && <Typography>{t('Not signed in')}</Typography>}\n </div>\n </div>\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n {user && <Item\n text={t('Account settings')}\n onClick={async () => await app.redirectToAccountSettings()}\n icon={<CircleUser {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign in')}\n onClick={async () => await app.redirectToSignIn()}\n icon={<LogIn {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign up')}\n onClick={async () => await app.redirectToSignUp()}\n icon={<UserPlus {...iconProps}/> }\n />}\n {user && props.extraItems && props.extraItems.map((item, index) => (\n <Item key={index} {...item} />\n ))}\n {props.colorModeToggle && (\n <Item\n text={t('Toggle theme')}\n onClick={props.colorModeToggle}\n icon={<SunMoon {...iconProps} />}\n />\n )}\n {user && <Item\n text={t('Sign out')}\n onClick={() => user.signOut()}\n icon={<LogOut {...iconProps} />}\n />}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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","names":[]}