nextworks 0.0.1 → 0.1.0-alpha.0

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 (277) hide show
  1. package/README.md +209 -30
  2. package/dist/.gitkeep +0 -0
  3. package/dist/cli_manifests/auth_manifest.json +86 -0
  4. package/dist/cli_manifests/blocks_manifest.json +185 -0
  5. package/dist/cli_manifests/data_manifest.json +51 -0
  6. package/dist/cli_manifests/forms_manifest.json +61 -0
  7. package/dist/commands/admin-posts.d.ts +2 -0
  8. package/dist/commands/admin-posts.d.ts.map +1 -0
  9. package/dist/commands/admin-posts.js +15 -0
  10. package/dist/commands/admin-posts.js.map +1 -0
  11. package/dist/commands/admin-users.d.ts +2 -0
  12. package/dist/commands/admin-users.d.ts.map +1 -0
  13. package/dist/commands/admin-users.js +15 -0
  14. package/dist/commands/admin-users.js.map +1 -0
  15. package/dist/commands/auth-core.d.ts +2 -0
  16. package/dist/commands/auth-core.d.ts.map +1 -0
  17. package/dist/commands/auth-core.js +83 -0
  18. package/dist/commands/auth-core.js.map +1 -0
  19. package/dist/commands/auth-forms.d.ts +2 -0
  20. package/dist/commands/auth-forms.d.ts.map +1 -0
  21. package/dist/commands/auth-forms.js +15 -0
  22. package/dist/commands/auth-forms.js.map +1 -0
  23. package/dist/commands/blocks-options.d.ts +7 -0
  24. package/dist/commands/blocks-options.d.ts.map +1 -0
  25. package/dist/commands/blocks-options.js +19 -0
  26. package/dist/commands/blocks-options.js.map +1 -0
  27. package/dist/commands/blocks.d.ts +7 -0
  28. package/dist/commands/blocks.d.ts.map +1 -0
  29. package/dist/commands/blocks.js +140 -0
  30. package/dist/commands/blocks.js.map +1 -0
  31. package/dist/commands/data.d.ts +3 -0
  32. package/dist/commands/data.d.ts.map +1 -0
  33. package/dist/commands/data.js +88 -0
  34. package/dist/commands/data.js.map +1 -0
  35. package/dist/commands/forms.d.ts +6 -0
  36. package/dist/commands/forms.d.ts.map +1 -0
  37. package/dist/commands/forms.js +107 -0
  38. package/dist/commands/forms.js.map +1 -0
  39. package/dist/commands/remove-auth-core.d.ts +2 -0
  40. package/dist/commands/remove-auth-core.d.ts.map +1 -0
  41. package/dist/commands/remove-auth-core.js +69 -0
  42. package/dist/commands/remove-auth-core.js.map +1 -0
  43. package/dist/commands/remove-blocks.d.ts +2 -0
  44. package/dist/commands/remove-blocks.d.ts.map +1 -0
  45. package/dist/commands/remove-blocks.js +36 -0
  46. package/dist/commands/remove-blocks.js.map +1 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +109 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/kits/auth-core/README.md +82 -0
  52. package/dist/kits/auth-core/app/(protected)/dashboard/page.tsx +8 -0
  53. package/dist/kits/auth-core/app/(protected)/layout.tsx +18 -0
  54. package/dist/kits/auth-core/app/(protected)/settings/profile/page.tsx +15 -0
  55. package/dist/kits/auth-core/app/(protected)/settings/profile/profile-form.tsx +114 -0
  56. package/dist/kits/auth-core/app/api/auth/[...nextauth]/route.ts +1 -0
  57. package/dist/kits/auth-core/app/api/auth/forgot-password/route.ts +114 -0
  58. package/dist/kits/auth-core/app/api/auth/providers/route.ts +6 -0
  59. package/dist/kits/auth-core/app/api/auth/reset-password/route.ts +63 -0
  60. package/dist/kits/auth-core/app/api/auth/send-verify-email/route.ts +6 -0
  61. package/dist/kits/auth-core/app/api/signup/route.ts +41 -0
  62. package/dist/kits/auth-core/app/auth/forgot-password/page.tsx +21 -0
  63. package/dist/kits/auth-core/app/auth/login/page.tsx +5 -0
  64. package/dist/kits/auth-core/app/auth/reset-password/page.tsx +187 -0
  65. package/dist/kits/auth-core/app/auth/signup/page.tsx +5 -0
  66. package/dist/kits/auth-core/app/auth/verify-email/page.tsx +11 -0
  67. package/dist/kits/auth-core/components/admin/admin-header.tsx +57 -0
  68. package/dist/kits/auth-core/components/auth/dashboard.tsx +237 -0
  69. package/dist/kits/auth-core/components/auth/forgot-password-form.tsx +90 -0
  70. package/dist/kits/auth-core/components/auth/login-form.tsx +467 -0
  71. package/dist/kits/auth-core/components/auth/logout-button.tsx +50 -0
  72. package/dist/kits/auth-core/components/auth/minimal-logout-button.tsx +40 -0
  73. package/dist/kits/auth-core/components/auth/signup-form.tsx +468 -0
  74. package/dist/kits/auth-core/components/require-auth.tsx +59 -0
  75. package/dist/kits/auth-core/components/session-provider.tsx +11 -0
  76. package/dist/kits/auth-core/components/ui/README.txt +1 -0
  77. package/dist/kits/auth-core/components/ui/button.tsx +55 -0
  78. package/dist/kits/auth-core/components/ui/input.tsx +25 -0
  79. package/dist/kits/auth-core/components/ui/label.tsx +23 -0
  80. package/dist/kits/auth-core/lib/api/errors.ts +14 -0
  81. package/dist/kits/auth-core/lib/auth-helpers.ts +29 -0
  82. package/dist/kits/auth-core/lib/auth.ts +142 -0
  83. package/dist/kits/auth-core/lib/email/dev-transport.ts +42 -0
  84. package/dist/kits/auth-core/lib/email/index.ts +28 -0
  85. package/dist/kits/auth-core/lib/email/provider-smtp.ts +36 -0
  86. package/dist/kits/auth-core/lib/forms/map-errors.ts +11 -0
  87. package/dist/kits/auth-core/lib/hash.ts +6 -0
  88. package/dist/kits/auth-core/lib/prisma.ts +15 -0
  89. package/dist/kits/auth-core/lib/server/result.ts +45 -0
  90. package/dist/kits/auth-core/lib/utils.ts +6 -0
  91. package/dist/kits/auth-core/lib/validation/forms.ts +88 -0
  92. package/dist/kits/auth-core/package-deps.json +19 -0
  93. package/dist/kits/auth-core/prisma/auth-models.prisma +81 -0
  94. package/dist/kits/auth-core/prisma/schema.prisma +81 -0
  95. package/dist/kits/auth-core/scripts/populate-tokenhash.mjs +26 -0
  96. package/dist/kits/auth-core/scripts/promote-admin.mjs +33 -0
  97. package/dist/kits/auth-core/scripts/seed-demo.mjs +40 -0
  98. package/dist/kits/auth-core/types/next-auth.d.ts +25 -0
  99. package/dist/kits/blocks/README.md +53 -0
  100. package/dist/kits/blocks/app/globals.css +175 -0
  101. package/dist/kits/blocks/app/templates/digitalagency/PresetThemeVars.tsx +80 -0
  102. package/dist/kits/blocks/app/templates/digitalagency/README.md +36 -0
  103. package/dist/kits/blocks/app/templates/digitalagency/components/About.tsx +99 -0
  104. package/dist/kits/blocks/app/templates/digitalagency/components/CTA.tsx +74 -0
  105. package/dist/kits/blocks/app/templates/digitalagency/components/Contact.tsx +227 -0
  106. package/dist/kits/blocks/app/templates/digitalagency/components/Footer.tsx +89 -0
  107. package/dist/kits/blocks/app/templates/digitalagency/components/Hero.tsx +90 -0
  108. package/dist/kits/blocks/app/templates/digitalagency/components/Navbar.tsx +168 -0
  109. package/dist/kits/blocks/app/templates/digitalagency/components/NetworkPattern.tsx +297 -0
  110. package/dist/kits/blocks/app/templates/digitalagency/components/Portfolio.tsx +157 -0
  111. package/dist/kits/blocks/app/templates/digitalagency/components/Pricing.tsx +114 -0
  112. package/dist/kits/blocks/app/templates/digitalagency/components/Process.tsx +59 -0
  113. package/dist/kits/blocks/app/templates/digitalagency/components/Services.tsx +55 -0
  114. package/dist/kits/blocks/app/templates/digitalagency/components/Team.tsx +28 -0
  115. package/dist/kits/blocks/app/templates/digitalagency/components/Testimonials.tsx +65 -0
  116. package/dist/kits/blocks/app/templates/digitalagency/page.tsx +38 -0
  117. package/dist/kits/blocks/app/templates/gallery/PresetThemeVars.tsx +85 -0
  118. package/dist/kits/blocks/app/templates/gallery/page.tsx +303 -0
  119. package/dist/kits/blocks/app/templates/productlaunch/PresetThemeVars.tsx +74 -0
  120. package/dist/kits/blocks/app/templates/productlaunch/README.md +55 -0
  121. package/dist/kits/blocks/app/templates/productlaunch/components/About.tsx +178 -0
  122. package/dist/kits/blocks/app/templates/productlaunch/components/CTA.tsx +93 -0
  123. package/dist/kits/blocks/app/templates/productlaunch/components/Contact.tsx +231 -0
  124. package/dist/kits/blocks/app/templates/productlaunch/components/FAQ.tsx +93 -0
  125. package/dist/kits/blocks/app/templates/productlaunch/components/Features.tsx +84 -0
  126. package/dist/kits/blocks/app/templates/productlaunch/components/Footer.tsx +132 -0
  127. package/dist/kits/blocks/app/templates/productlaunch/components/Hero.tsx +89 -0
  128. package/dist/kits/blocks/app/templates/productlaunch/components/Navbar.tsx +162 -0
  129. package/dist/kits/blocks/app/templates/productlaunch/components/Pricing.tsx +106 -0
  130. package/dist/kits/blocks/app/templates/productlaunch/components/ProcessTimeline.tsx +110 -0
  131. package/dist/kits/blocks/app/templates/productlaunch/components/ServicesGrid.tsx +68 -0
  132. package/dist/kits/blocks/app/templates/productlaunch/components/Team.tsx +104 -0
  133. package/dist/kits/blocks/app/templates/productlaunch/components/Testimonials.tsx +89 -0
  134. package/dist/kits/blocks/app/templates/productlaunch/components/TrustBadges.tsx +76 -0
  135. package/dist/kits/blocks/app/templates/productlaunch/page.tsx +45 -0
  136. package/dist/kits/blocks/app/templates/saasdashboard/PresetThemeVars.tsx +80 -0
  137. package/dist/kits/blocks/app/templates/saasdashboard/README.md +38 -0
  138. package/dist/kits/blocks/app/templates/saasdashboard/components/Contact.tsx +176 -0
  139. package/dist/kits/blocks/app/templates/saasdashboard/components/Dashboard.tsx +293 -0
  140. package/dist/kits/blocks/app/templates/saasdashboard/components/FAQ.tsx +55 -0
  141. package/dist/kits/blocks/app/templates/saasdashboard/components/Features.tsx +91 -0
  142. package/dist/kits/blocks/app/templates/saasdashboard/components/Footer.tsx +77 -0
  143. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero.tsx +105 -0
  144. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero_mask.tsx +127 -0
  145. package/dist/kits/blocks/app/templates/saasdashboard/components/Navbar.tsx +159 -0
  146. package/dist/kits/blocks/app/templates/saasdashboard/components/Pricing.tsx +90 -0
  147. package/dist/kits/blocks/app/templates/saasdashboard/components/SmoothScroll.tsx +97 -0
  148. package/dist/kits/blocks/app/templates/saasdashboard/components/Testimonials.tsx +72 -0
  149. package/dist/kits/blocks/app/templates/saasdashboard/components/TrustBadges.tsx +53 -0
  150. package/dist/kits/blocks/app/templates/saasdashboard/page.tsx +39 -0
  151. package/dist/kits/blocks/components/app-providers.tsx +1 -0
  152. package/dist/kits/blocks/components/enhanced-theme-provider.tsx +195 -0
  153. package/dist/kits/blocks/components/sections/About.tsx +291 -0
  154. package/dist/kits/blocks/components/sections/CTA.tsx +258 -0
  155. package/dist/kits/blocks/components/sections/Contact.tsx +267 -0
  156. package/dist/kits/blocks/components/sections/FAQ.tsx +226 -0
  157. package/dist/kits/blocks/components/sections/Features.tsx +269 -0
  158. package/dist/kits/blocks/components/sections/Footer.tsx +302 -0
  159. package/dist/kits/blocks/components/sections/HeroMotion.tsx +307 -0
  160. package/dist/kits/blocks/components/sections/HeroOverlay.tsx +358 -0
  161. package/dist/kits/blocks/components/sections/HeroSplit.tsx +352 -0
  162. package/dist/kits/blocks/components/sections/Navbar.tsx +353 -0
  163. package/dist/kits/blocks/components/sections/Newsletter.tsx +156 -0
  164. package/dist/kits/blocks/components/sections/PortfolioSimple.tsx +550 -0
  165. package/dist/kits/blocks/components/sections/Pricing.tsx +264 -0
  166. package/dist/kits/blocks/components/sections/ProcessTimeline.tsx +325 -0
  167. package/dist/kits/blocks/components/sections/ServicesGrid.tsx +210 -0
  168. package/dist/kits/blocks/components/sections/Team.tsx +309 -0
  169. package/dist/kits/blocks/components/sections/Testimonials.tsx +158 -0
  170. package/dist/kits/blocks/components/sections/TrustBadges.tsx +162 -0
  171. package/dist/kits/blocks/components/theme-provider.tsx +34 -0
  172. package/dist/kits/blocks/components/ui/alert-dialog.tsx +134 -0
  173. package/dist/kits/blocks/components/ui/brand-node.tsx +121 -0
  174. package/dist/kits/blocks/components/ui/button.tsx +122 -0
  175. package/dist/kits/blocks/components/ui/button_bck.tsx +93 -0
  176. package/dist/kits/blocks/components/ui/card.tsx +95 -0
  177. package/dist/kits/blocks/components/ui/checkbox.tsx +30 -0
  178. package/dist/kits/blocks/components/ui/cta-button.tsx +125 -0
  179. package/dist/kits/blocks/components/ui/dropdown-menu.tsx +201 -0
  180. package/dist/kits/blocks/components/ui/feature-card.tsx +91 -0
  181. package/dist/kits/blocks/components/ui/input.tsx +27 -0
  182. package/dist/kits/blocks/components/ui/label.tsx +29 -0
  183. package/dist/kits/blocks/components/ui/pricing-card.tsx +120 -0
  184. package/dist/kits/blocks/components/ui/select.tsx +25 -0
  185. package/dist/kits/blocks/components/ui/skeleton.tsx +13 -0
  186. package/dist/kits/blocks/components/ui/switch.tsx +78 -0
  187. package/dist/kits/blocks/components/ui/table.tsx +98 -0
  188. package/dist/kits/blocks/components/ui/testimonial-card.tsx +108 -0
  189. package/dist/kits/blocks/components/ui/textarea.tsx +26 -0
  190. package/dist/kits/blocks/components/ui/theme-selector.tsx +247 -0
  191. package/dist/kits/blocks/components/ui/theme-toggle.tsx +74 -0
  192. package/dist/kits/blocks/components/ui/toaster.tsx +7 -0
  193. package/dist/kits/blocks/lib/themes.ts +399 -0
  194. package/dist/kits/blocks/lib/themes_old.ts +37 -0
  195. package/dist/kits/blocks/lib/utils.ts +9 -0
  196. package/dist/kits/blocks/next.config.ts +11 -0
  197. package/dist/kits/blocks/notes/THEME_GUIDE.md +29 -0
  198. package/dist/kits/blocks/notes/THEMING_CONVERSION_SUMMARY.md +14 -0
  199. package/dist/kits/blocks/package-deps.json +22 -0
  200. package/dist/kits/blocks/public/placeholders/gallery/hero-pexels-broken-9945014.avif +0 -0
  201. package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626431.jpg +0 -0
  202. package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626432.jpg +0 -0
  203. package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626434.jpg +0 -0
  204. package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626436.jpg +0 -0
  205. package/dist/kits/blocks/public/placeholders/product_launch/feature_1.png +0 -0
  206. package/dist/kits/blocks/public/placeholders/product_launch/feature_2.png +0 -0
  207. package/dist/kits/blocks/public/placeholders/product_launch/feature_3.png +0 -0
  208. package/dist/kits/blocks/public/placeholders/product_launch/feature_4.png +0 -0
  209. package/dist/kits/blocks/public/placeholders/product_launch/hero.png +0 -0
  210. package/dist/kits/blocks/public/placeholders/saas_dashboard/analytics.png +0 -0
  211. package/dist/kits/blocks/public/placeholders/saas_dashboard/chat.png +0 -0
  212. package/dist/kits/blocks/public/placeholders/saas_dashboard/projectBoard.png +0 -0
  213. package/dist/kits/data/.gitkeep +0 -0
  214. package/dist/kits/data/README.md +80 -0
  215. package/dist/kits/data/app/(protected)/admin/posts/page.tsx +5 -0
  216. package/dist/kits/data/app/(protected)/admin/users/page.tsx +5 -0
  217. package/dist/kits/data/app/api/posts/[id]/route.ts +83 -0
  218. package/dist/kits/data/app/api/posts/route.ts +138 -0
  219. package/dist/kits/data/app/api/seed-demo/route.ts +45 -0
  220. package/dist/kits/data/app/api/users/[id]/route.ts +127 -0
  221. package/dist/kits/data/app/api/users/check-email/route.ts +18 -0
  222. package/dist/kits/data/app/api/users/check-unique/route.ts +27 -0
  223. package/dist/kits/data/app/api/users/route.ts +79 -0
  224. package/dist/kits/data/app/examples/demo/README.md +4 -0
  225. package/dist/kits/data/app/examples/demo/create-post-form.tsx +106 -0
  226. package/dist/kits/data/app/examples/demo/page.tsx +118 -0
  227. package/dist/kits/data/app/examples/demo/seed-demo-button.tsx +37 -0
  228. package/dist/kits/data/components/admin/posts-manager.tsx +719 -0
  229. package/dist/kits/data/components/admin/users-manager.tsx +432 -0
  230. package/dist/kits/data/lib/prisma.ts +15 -0
  231. package/dist/kits/data/lib/server/result.ts +90 -0
  232. package/dist/kits/data/package-deps.json +11 -0
  233. package/dist/kits/data/scripts/seed-demo.mjs +41 -0
  234. package/dist/kits/forms/.gitkeep +0 -0
  235. package/dist/kits/forms/README.md +49 -0
  236. package/dist/kits/forms/app/.gitkeep +0 -0
  237. package/dist/kits/forms/app/api/wizard/route.ts +71 -0
  238. package/dist/kits/forms/app/examples/forms/basic/page.tsx +124 -0
  239. package/dist/kits/forms/app/examples/forms/server-action/form-client.tsx +28 -0
  240. package/dist/kits/forms/app/examples/forms/server-action/page.tsx +71 -0
  241. package/dist/kits/forms/app/examples/forms/wizard/page.tsx +15 -0
  242. package/dist/kits/forms/app/examples/forms/wizard/wizard-client.tsx +2 -0
  243. package/dist/kits/forms/components/.gitkeep +0 -0
  244. package/dist/kits/forms/components/examples/wizard-client.tsx +231 -0
  245. package/dist/kits/forms/components/hooks/useCheckUnique.ts +79 -0
  246. package/dist/kits/forms/components/ui/button.tsx +122 -0
  247. package/dist/kits/forms/components/ui/checkbox.tsx +30 -0
  248. package/dist/kits/forms/components/ui/form/context.ts +33 -0
  249. package/dist/kits/forms/components/ui/form/form-control.tsx +28 -0
  250. package/dist/kits/forms/components/ui/form/form-description.tsx +22 -0
  251. package/dist/kits/forms/components/ui/form/form-field.tsx +36 -0
  252. package/dist/kits/forms/components/ui/form/form-item.tsx +21 -0
  253. package/dist/kits/forms/components/ui/form/form-label.tsx +24 -0
  254. package/dist/kits/forms/components/ui/form/form-message.tsx +29 -0
  255. package/dist/kits/forms/components/ui/form/form.tsx +26 -0
  256. package/dist/kits/forms/components/ui/input.tsx +27 -0
  257. package/dist/kits/forms/components/ui/label.tsx +29 -0
  258. package/dist/kits/forms/components/ui/select.tsx +25 -0
  259. package/dist/kits/forms/components/ui/switch.tsx +78 -0
  260. package/dist/kits/forms/components/ui/textarea.tsx +26 -0
  261. package/dist/kits/forms/lib/.gitkeep +0 -0
  262. package/dist/kits/forms/lib/forms/map-errors.ts +29 -0
  263. package/dist/kits/forms/lib/prisma.ts +16 -0
  264. package/dist/kits/forms/lib/utils.ts +9 -0
  265. package/dist/kits/forms/lib/validation/forms.ts +88 -0
  266. package/dist/kits/forms/lib/validation/wizard.ts +32 -0
  267. package/dist/kits/forms/package-deps.json +17 -0
  268. package/dist/utils/file-operations.d.ts +18 -0
  269. package/dist/utils/file-operations.d.ts.map +1 -0
  270. package/dist/utils/file-operations.js +327 -0
  271. package/dist/utils/file-operations.js.map +1 -0
  272. package/dist/utils/installation-tracker.d.ts +26 -0
  273. package/dist/utils/installation-tracker.d.ts.map +1 -0
  274. package/dist/utils/installation-tracker.js +98 -0
  275. package/dist/utils/installation-tracker.js.map +1 -0
  276. package/package.json +51 -21
  277. package/index.js +0 -1
@@ -0,0 +1,122 @@
1
+ import * as React from "react";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const buttonVariants = cva(
8
+ "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "bg-primary text-primary-foreground hover:bg-primary/90 shadow-xs",
14
+ destructive:
15
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 shadow-xs",
16
+ outline:
17
+ "bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border shadow-xs",
18
+ secondary:
19
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs",
20
+ ghost:
21
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22
+ link: "text-primary underline-offset-4 hover:underline",
23
+ },
24
+ size: {
25
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
26
+ sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
27
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28
+ icon: "size-9",
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ variant: "default",
33
+ size: "default",
34
+ },
35
+ },
36
+ );
37
+
38
+ type ButtonProps = React.ComponentProps<"button"> &
39
+ VariantProps<typeof buttonVariants> & {
40
+ asChild?: boolean;
41
+ /** When true, bypasses tokenized buttonVariants so callers fully control classes */
42
+ unstyled?: boolean;
43
+ /** Opt-in: force inline CSS var styles for color/bg/border/ring */
44
+ forceInlineVars?: boolean;
45
+ };
46
+
47
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
48
+ (
49
+ {
50
+ className,
51
+ variant,
52
+ size,
53
+ asChild = false,
54
+ unstyled = false,
55
+ forceInlineVars = false,
56
+ ...props
57
+ },
58
+ ref,
59
+ ) => {
60
+ const Comp = asChild ? Slot : "button";
61
+
62
+ // Use caller-provided style; only inject inline var-driven colors when explicitly requested
63
+ const incomingStyle =
64
+ (props.style as React.CSSProperties | undefined) ?? undefined;
65
+ const finalStyle =
66
+ forceInlineVars && !unstyled
67
+ ? {
68
+ ...incomingStyle,
69
+ color: "var(--btn-fg)",
70
+ backgroundColor: "var(--btn-bg)",
71
+ borderColor: "var(--btn-border)",
72
+ "--tw-ring-color": "var(--btn-ring)",
73
+ }
74
+ : incomingStyle;
75
+
76
+ // Only enable CSS variable hooks when explicitly requested via inline vars
77
+ // or when the caller sets any [--btn-*] classes in className.
78
+ const wantsVarHooks =
79
+ !unstyled &&
80
+ (forceInlineVars ||
81
+ (typeof className === "string" && className.includes("[--btn-")));
82
+
83
+ return (
84
+ <Comp
85
+ ref={ref}
86
+ data-slot="button"
87
+ className={
88
+ unstyled
89
+ ? cn(
90
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap disabled:pointer-events-none disabled:opacity-50",
91
+ className,
92
+ )
93
+ : cn(
94
+ buttonVariants({ variant, size }),
95
+ wantsVarHooks && [
96
+ // Color var hooks (apply only when CSS vars are provided)
97
+ "text-[var(--btn-fg)]",
98
+ "bg-[var(--btn-bg)]",
99
+ "hover:bg-[var(--btn-hover-bg)]",
100
+ "hover:text-[var(--btn-hover-fg)]",
101
+ // explicit dark variants to compete with dark: utilities from variants like outline
102
+ "dark:bg-[var(--btn-bg)]",
103
+ "dark:hover:bg-[var(--btn-hover-bg)]",
104
+ "dark:hover:text-[var(--btn-hover-fg)]",
105
+ // Focus ring and border hooks
106
+ "focus-visible:ring-[var(--btn-ring)]",
107
+ "border-[var(--btn-border)]",
108
+ "dark:border-[var(--btn-border)]",
109
+ ],
110
+ className,
111
+ )
112
+ }
113
+ style={finalStyle}
114
+ {...props}
115
+ />
116
+ );
117
+ },
118
+ );
119
+
120
+ Button.displayName = "Button";
121
+
122
+ export { Button, buttonVariants };
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ export type CheckboxProps = React.InputHTMLAttributes<HTMLInputElement>;
5
+
6
+ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
7
+ ({ className, ...props }, ref) => {
8
+ // Use the native accent-color where supported for consistent checkbox fill
9
+ const style: React.CSSProperties = { accentColor: "var(--primary)" }; // fallback; modern browsers will use this accent color
10
+
11
+ return (
12
+ <input
13
+ type="checkbox"
14
+ ref={ref}
15
+ style={style}
16
+ className={cn(
17
+ // Keep layout small but add smooth transitions and focus ring
18
+ "h-4 w-4 rounded border-[var(--input-border)] bg-[var(--input-bg)] text-[var(--input-fg)] transition-colors duration-200 ease-in-out",
19
+ "focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:outline-none",
20
+ "disabled:cursor-not-allowed disabled:opacity-50",
21
+ className,
22
+ )}
23
+ {...props}
24
+ />
25
+ );
26
+ },
27
+ );
28
+ Checkbox.displayName = "Checkbox";
29
+
30
+ export { Checkbox };
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ import { useFormContext } from "react-hook-form";
3
+
4
+ export const FormFieldContext = React.createContext<{ name: string } | null>(
5
+ null,
6
+ );
7
+
8
+ export const FormItemContext = React.createContext<{ id: string } | null>(null);
9
+
10
+ export function useFormField() {
11
+ const fieldContext = React.useContext(FormFieldContext);
12
+ const itemContext = React.useContext(FormItemContext);
13
+ const { getFieldState, formState } = useFormContext();
14
+
15
+ if (!fieldContext) {
16
+ throw new Error("useFormField should be used within <FormField>");
17
+ }
18
+ if (!itemContext) {
19
+ throw new Error("useFormField should be used within <FormItem>");
20
+ }
21
+
22
+ const fieldState = getFieldState(fieldContext.name, formState);
23
+ const id = itemContext.id;
24
+
25
+ return {
26
+ id,
27
+ name: fieldContext.name,
28
+ formItemId: `${id}-form-item`,
29
+ formDescriptionId: `${id}-form-item-description`,
30
+ formMessageId: `${id}-form-item-message`,
31
+ ...fieldState,
32
+ } as const;
33
+ }
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { useFormField } from "./context";
5
+ import { Slot } from "@radix-ui/react-slot";
6
+
7
+ export interface FormControlProps
8
+ extends React.ComponentPropsWithoutRef<typeof Slot> {}
9
+
10
+ export const FormControl = React.forwardRef<
11
+ React.ElementRef<typeof Slot>,
12
+ FormControlProps
13
+ >(({ ...props }, ref) => {
14
+ const { formItemId, formDescriptionId, formMessageId, error } =
15
+ useFormField();
16
+ return (
17
+ <Slot
18
+ ref={ref}
19
+ id={formItemId}
20
+ aria-describedby={
21
+ error ? `${formDescriptionId} ${formMessageId}` : formDescriptionId
22
+ }
23
+ aria-invalid={!!error}
24
+ {...props}
25
+ />
26
+ );
27
+ });
28
+ FormControl.displayName = "FormControl";
@@ -0,0 +1,22 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { useFormField } from "./context";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ export interface FormDescriptionProps
8
+ extends React.HTMLAttributes<HTMLParagraphElement> {}
9
+
10
+ export const FormDescription = ({
11
+ className,
12
+ ...props
13
+ }: FormDescriptionProps) => {
14
+ const { formDescriptionId } = useFormField();
15
+ return (
16
+ <p
17
+ id={formDescriptionId}
18
+ className={cn("text-xs text-muted-foreground", className)}
19
+ {...props}
20
+ />
21
+ );
22
+ };
@@ -0,0 +1,36 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import {
5
+ Controller,
6
+ type ControllerProps,
7
+ type FieldPath,
8
+ type FieldValues,
9
+ } from "react-hook-form";
10
+ import { FormFieldContext } from "./context";
11
+
12
+ export interface FormFieldProps<
13
+ TFieldValues extends FieldValues,
14
+ TName extends FieldPath<TFieldValues>,
15
+ > extends Omit<ControllerProps<TFieldValues, TName>, "render"> {
16
+ render: ControllerProps<TFieldValues, TName>["render"];
17
+ }
18
+
19
+ export function FormField<
20
+ TFieldValues extends FieldValues,
21
+ TName extends FieldPath<TFieldValues>,
22
+ >(props: FormFieldProps<TFieldValues, TName>) {
23
+ const { name, control, rules, shouldUnregister, render } = props;
24
+
25
+ return (
26
+ <FormFieldContext.Provider value={{ name: name as string }}>
27
+ <Controller
28
+ name={name}
29
+ control={control}
30
+ rules={rules}
31
+ shouldUnregister={shouldUnregister}
32
+ render={render}
33
+ />
34
+ </FormFieldContext.Provider>
35
+ );
36
+ }
@@ -0,0 +1,21 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { cn } from "@/lib/utils";
5
+ import { FormItemContext } from "./context";
6
+
7
+ export interface FormItemProps
8
+ extends React.HTMLAttributes<HTMLDivElement> {}
9
+
10
+ export const FormItem = React.forwardRef<HTMLDivElement, FormItemProps>(
11
+ ({ className, ...props }, ref) => {
12
+ const id = React.useId();
13
+
14
+ return (
15
+ <FormItemContext.Provider value={{ id }}>
16
+ <div ref={ref} className={cn("space-y-2", className)} {...props} />
17
+ </FormItemContext.Provider>
18
+ );
19
+ },
20
+ );
21
+ FormItem.displayName = "FormItem";
@@ -0,0 +1,24 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Label } from "@/components/ui/label";
5
+ import { useFormField } from "./context";
6
+ import { cn } from "@/lib/utils";
7
+
8
+ export interface FormLabelProps extends React.ComponentProps<typeof Label> {}
9
+
10
+ export const FormLabel = React.forwardRef<
11
+ React.ElementRef<typeof Label>,
12
+ FormLabelProps
13
+ >(({ className, ...props }, ref) => {
14
+ const { formItemId } = useFormField();
15
+ return (
16
+ <Label
17
+ ref={ref}
18
+ htmlFor={formItemId}
19
+ className={cn(className)}
20
+ {...props}
21
+ />
22
+ );
23
+ });
24
+ FormLabel.displayName = "FormLabel";
@@ -0,0 +1,29 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { useFormField } from "./context";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ export interface FormMessageProps
8
+ extends React.HTMLAttributes<HTMLParagraphElement> {}
9
+
10
+ export const FormMessage = ({
11
+ className,
12
+ children,
13
+ ...props
14
+ }: FormMessageProps) => {
15
+ const { error, formMessageId } = useFormField();
16
+ const body = error ? String(error.message || children) : children;
17
+
18
+ if (!body) return null;
19
+
20
+ return (
21
+ <p
22
+ id={formMessageId}
23
+ className={cn("text-xs text-destructive", className)}
24
+ {...props}
25
+ >
26
+ {body}
27
+ </p>
28
+ );
29
+ };
@@ -0,0 +1,26 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import {
5
+ FormProvider,
6
+ type UseFormReturn,
7
+ type FieldValues,
8
+ } from "react-hook-form";
9
+
10
+ export interface FormProps<TFieldValues extends FieldValues = FieldValues> {
11
+ children: React.ReactNode;
12
+ className?: string;
13
+ methods: UseFormReturn<TFieldValues>;
14
+ }
15
+
16
+ export function Form<TFieldValues extends FieldValues = FieldValues>({
17
+ children,
18
+ className,
19
+ methods,
20
+ }: FormProps<TFieldValues>) {
21
+ return (
22
+ <FormProvider<TFieldValues> {...methods}>
23
+ <div className={className}>{children}</div>
24
+ </FormProvider>
25
+ );
26
+ }
@@ -0,0 +1,27 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "@/lib/utils";
4
+
5
+ export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
6
+
7
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
8
+ ({ className, type, ...props }, ref) => {
9
+ return (
10
+ <input
11
+ type={type}
12
+ className={cn(
13
+ // Base structural + token fallbacks
14
+ "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive/30 dark:aria-invalid:focus-visible:ring-destructive/40 flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
15
+ // CSS variable hooks (preset-first). When vars are unset, these are ignored and tokens above apply.
16
+ "focus-visible:ring-offset-background border-[var(--input-border)] bg-[var(--input-bg)] text-[var(--input-fg)] placeholder:text-[var(--input-placeholder)] focus-visible:ring-[var(--input-focus-ring,var(--ring))] focus-visible:ring-offset-2",
17
+ className,
18
+ )}
19
+ ref={ref}
20
+ {...props}
21
+ />
22
+ );
23
+ },
24
+ );
25
+ Input.displayName = "Input";
26
+
27
+ export { Input };
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ import * as LabelPrimitive from "@radix-ui/react-label";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const labelVariants = cva(
8
+ "text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
9
+ );
10
+
11
+ const Label = React.forwardRef<
12
+ React.ElementRef<typeof LabelPrimitive.Root>,
13
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
14
+ VariantProps<typeof labelVariants>
15
+ >(({ className, ...props }, ref) => (
16
+ <LabelPrimitive.Root
17
+ ref={ref}
18
+ className={cn(
19
+ labelVariants(),
20
+ // Optional color override via var; falls back to inherited color when unset
21
+ "text-[var(--label-fg)]",
22
+ className,
23
+ )}
24
+ {...props}
25
+ />
26
+ ));
27
+ Label.displayName = LabelPrimitive.Root.displayName;
28
+
29
+ export { Label };
@@ -0,0 +1,25 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ export type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement>;
5
+
6
+ const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
7
+ ({ className, children, ...props }, ref) => {
8
+ return (
9
+ <select
10
+ ref={ref}
11
+ className={cn(
12
+ "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive/30 dark:aria-invalid:focus-visible:ring-destructive/40 flex h-10 w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
13
+ "bg-[var(--input-bg)] text-[var(--input-fg)]",
14
+ className,
15
+ )}
16
+ {...props}
17
+ >
18
+ {children}
19
+ </select>
20
+ );
21
+ },
22
+ );
23
+ Select.displayName = "Select";
24
+
25
+ export { Select };
@@ -0,0 +1,78 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ export type SwitchProps = React.InputHTMLAttributes<HTMLInputElement> & {
5
+ isLoading?: boolean;
6
+ };
7
+
8
+ const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
9
+ ({ className, isLoading, disabled, ...props }, ref) => {
10
+ const checked = !!(props as any).checked;
11
+ const isDisabled = !!disabled || !!isLoading;
12
+ return (
13
+ <label
14
+ className={cn(
15
+ "focus-within:ring-offset-background inline-flex items-center rounded-full focus-within:ring-2 focus-within:ring-[var(--ring)] focus-within:ring-offset-2",
16
+ isDisabled ? "cursor-not-allowed opacity-80" : "cursor-pointer",
17
+ className,
18
+ )}
19
+ >
20
+ <input
21
+ type="checkbox"
22
+ role="switch"
23
+ ref={ref}
24
+ className="sr-only"
25
+ disabled={isDisabled}
26
+ aria-busy={isLoading ? "true" : undefined}
27
+ {...(props as any)}
28
+ />
29
+ <span
30
+ aria-hidden
31
+ className={cn(
32
+ "relative inline-flex h-6 w-11 flex-shrink-0 rounded-full transition-colors duration-200",
33
+ checked ? "bg-[var(--primary)]" : "bg-[var(--primary)]/80",
34
+ )}
35
+ >
36
+ <span
37
+ className={cn(
38
+ // Thumb should adjust for theme to guarantee contrast
39
+ "absolute top-0.5 left-0.5 h-5 w-5 transform rounded-full bg-[var(--switch-thumb)] shadow-md transition-transform duration-200 ease-in-out",
40
+ checked ? "translate-x-5" : "translate-x-0",
41
+ )}
42
+ />
43
+
44
+ {/* Loading indicator centered inside the switch when isLoading */}
45
+ {isLoading && (
46
+ <span className="absolute inset-0 flex items-center justify-center">
47
+ <svg
48
+ className="h-4 w-4 animate-spin text-white"
49
+ xmlns="http://www.w3.org/2000/svg"
50
+ fill="none"
51
+ viewBox="0 0 24 24"
52
+ aria-hidden
53
+ >
54
+ <circle
55
+ className="opacity-25"
56
+ cx="12"
57
+ cy="12"
58
+ r="10"
59
+ stroke="currentColor"
60
+ strokeWidth="4"
61
+ />
62
+ <path
63
+ className="opacity-75"
64
+ fill="currentColor"
65
+ d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
66
+ />
67
+ </svg>
68
+ </span>
69
+ )}
70
+ </span>
71
+ </label>
72
+ );
73
+ },
74
+ );
75
+
76
+ Switch.displayName = "Switch";
77
+
78
+ export { Switch };
@@ -0,0 +1,26 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "@/lib/utils";
4
+
5
+ export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
6
+
7
+ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
8
+ ({ className, ...props }, ref) => {
9
+ return (
10
+ <textarea
11
+ className={cn(
12
+ // Base structural + token fallbacks
13
+ "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive/30 dark:aria-invalid:focus-visible:ring-destructive/40 flex min-h-[80px] w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
14
+ // CSS variable hooks (preset-first). When vars are unset, tokens above apply.
15
+ "border-[var(--input-border)] bg-[var(--input-bg)] text-[var(--input-fg)] placeholder:text-[var(--input-placeholder)] focus-visible:ring-[var(--input-focus-ring)] focus-visible:ring-offset-[var(--input-ring-offset)]",
16
+ className,
17
+ )}
18
+ ref={ref}
19
+ {...props}
20
+ />
21
+ );
22
+ },
23
+ );
24
+ Textarea.displayName = "Textarea";
25
+
26
+ export { Textarea };
File without changes
@@ -0,0 +1,29 @@
1
+ import type { FieldValues, Path, UseFormReturn } from "react-hook-form";
2
+ import type { ApiResult } from "@/lib/server/result";
3
+
4
+ export function mapApiErrorsToForm<TFieldValues extends FieldValues>(
5
+ form: UseFormReturn<TFieldValues>,
6
+ result: ApiResult<any>,
7
+ options?: { formKey?: string },
8
+ ): string | undefined {
9
+ if (!result || result.success) return undefined;
10
+
11
+ const formKey = options?.formKey ?? "form";
12
+ let globalMessage = result.message;
13
+
14
+ const entries = Object.entries(result.errors ?? {});
15
+ for (const [key, message] of entries) {
16
+ if (!message) continue;
17
+ if (key === formKey) {
18
+ globalMessage = message;
19
+ continue;
20
+ }
21
+ try {
22
+ form.setError(key as Path<TFieldValues>, { type: "server", message });
23
+ } catch {
24
+ globalMessage = globalMessage ?? message;
25
+ }
26
+ }
27
+
28
+ return globalMessage;
29
+ }
@@ -0,0 +1,16 @@
1
+ import "server-only";
2
+
3
+ import { PrismaClient } from "@prisma/client";
4
+
5
+ const globalForPrisma = globalThis as unknown as {
6
+ prisma: PrismaClient | undefined;
7
+ };
8
+
9
+ export const prisma =
10
+ globalForPrisma.prisma ??
11
+ new PrismaClient({
12
+ log: ["error", "warn"],
13
+ });
14
+
15
+ if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
16
+
@@ -0,0 +1,9 @@
1
+ // Copyright (c) 2025 Jakob Bro Liebe Hansen
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { clsx, type ClassValue } from "clsx";
5
+ import { twMerge } from "tailwind-merge";
6
+
7
+ export function cn(...inputs: ClassValue[]) {
8
+ return twMerge(clsx(inputs));
9
+ }