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,353 @@
1
+ // components/sections/Navbar.tsx
2
+
3
+ "use client";
4
+
5
+ import React, { useEffect, useRef, useState } from "react";
6
+ import Link from "next/link";
7
+ import { Button } from "@/components/ui/button";
8
+ import {
9
+ ThemeToggle,
10
+ type ThemeToggleProps,
11
+ } from "@/components/ui/theme-toggle";
12
+ import { cn } from "@/lib/utils";
13
+ import { Menu, X } from "lucide-react";
14
+
15
+ /**
16
+ * Props for the Navbar component.
17
+ *
18
+ * @remarks
19
+ * Slot-style className overrides are available for structural parts. The mobile
20
+ * menu locks body scroll when open and restores it on close/unmount.
21
+ *
22
+ * @public
23
+ */
24
+ export interface NavbarProps {
25
+ /** Optional id to attach to the root nav element */
26
+ id?: string;
27
+
28
+ /** The height of the navbar as a Tailwind class. Example: "h-16" or "h-[13vh]" */
29
+ navHeight?: string;
30
+
31
+ /**
32
+ * The text displayed as the brand/logo.
33
+ * @defaultValue "Brand Name"
34
+ */
35
+ brand?: string;
36
+ /** Optional custom brand node (e.g., logo). Rendered left of brand text */
37
+ brandNode?: React.ReactNode;
38
+
39
+ /** Navigation links array. Each item has a label and href */
40
+ menuItems?: { label: string; href: string }[];
41
+
42
+ /**
43
+ * Call to action button config or null to hide it.
44
+ * Example: { label: "Get Started", href: "#contact" }
45
+ */
46
+ ctaButton?: { label: string; href: string } | null;
47
+
48
+ /**
49
+ * Whether to display the color mode toggle.
50
+ * @defaultValue true
51
+ */
52
+ showColorModeToggle?: boolean;
53
+
54
+ /**
55
+ * Whether navbar should stick to top when scrolling.
56
+ * @defaultValue true
57
+ */
58
+ sticky?: boolean;
59
+
60
+ /** Optional top-level class to override the nav root */
61
+ className?: string;
62
+
63
+ /** Styling configuration objects */
64
+ nav?: {
65
+ className?: string;
66
+ };
67
+
68
+ brandText?: {
69
+ className?: string;
70
+ };
71
+ links?: {
72
+ className?: string;
73
+ };
74
+ ctaButtonStyle?: {
75
+ unstyled?: boolean;
76
+ style?: React.CSSProperties;
77
+ variant?:
78
+ | "default"
79
+ | "destructive"
80
+ | "outline"
81
+ | "secondary"
82
+ | "ghost"
83
+ | "link";
84
+ size?: "default" | "sm" | "lg" | "icon";
85
+ className?: string;
86
+ };
87
+ mobileMenu?: {
88
+ className?: string;
89
+ };
90
+
91
+ /* Additional style slots for targeted overrides */
92
+ container?: { className?: string };
93
+ brandWrapper?: { className?: string };
94
+ desktopMenu?: { className?: string };
95
+ toggleButton?: { className?: string };
96
+ colorModeWrapper?: { className?: string };
97
+ ctaButtonWrapper?: { className?: string };
98
+ mobileMenuInner?: { className?: string };
99
+ /** Additional class overrides for mobile menu link hover/background, etc. */
100
+ mobileLinks?: { className?: string };
101
+
102
+ /** Props forwarded to ThemeToggle so templates can fully style it */
103
+ themeToggle?: ThemeToggleProps;
104
+
105
+ /** ARIA label for the navbar. */
106
+ ariaLabel?: string;
107
+ }
108
+
109
+ const defaultMenuItems = [
110
+ { label: "Home", href: "#home" },
111
+ { label: "Features", href: "#features" },
112
+ { label: "Pricing", href: "#pricing" },
113
+ { label: "FAQ", href: "#faq" },
114
+ { label: "Contact", href: "#contact" },
115
+ ];
116
+
117
+ /**
118
+ * Responsive navbar with brand, menu links, color mode toggle, and optional CTA.
119
+ *
120
+ * @remarks
121
+ * - Sticky behavior is enabled by default (sticky top-0 z-50).
122
+ * - Mobile menu toggles with a button and traps body scroll while open.
123
+ * - Accessibility: Focus rings are applied to interactive elements; aria
124
+ * attributes are set on the toggle button for state.
125
+ *
126
+ * @example
127
+ * <Navbar brand="Acme" />
128
+ */
129
+ export function Navbar({
130
+ id,
131
+ navHeight = "h-16",
132
+ brand = "Brand Name",
133
+ brandNode,
134
+ menuItems = defaultMenuItems,
135
+ ctaButton = { label: "Get Started", href: "#contact" },
136
+ showColorModeToggle = true,
137
+ sticky = true,
138
+ className,
139
+ nav = {
140
+ className: "bg-background text-foreground border-b border-border",
141
+ },
142
+ brandText = {
143
+ className: "text-2xl font-bold text-primary",
144
+ },
145
+ links = {
146
+ className:
147
+ "text-base font-normal text-foreground hover:text-gray-500 dark:hover-text-gray-400 transition-colors",
148
+ },
149
+ ctaButtonStyle = {
150
+ variant: "default",
151
+ size: "default",
152
+ className:
153
+ "shadow-lg hover:shadow-xl transition-all duration-200 hover:-translate-y-0.5",
154
+ },
155
+ mobileMenu = {
156
+ className: "border-t border-border",
157
+ },
158
+
159
+ /* new slot defaults */
160
+ container = { className: "" },
161
+ brandWrapper = { className: "" },
162
+ desktopMenu = {
163
+ className: "hidden items-center space-x-1 lg:flex lg:space-x-6",
164
+ },
165
+ toggleButton = {
166
+ className:
167
+ "hover:bg-accent flex items-center justify-center rounded-md p-2 transition-colors",
168
+ },
169
+ colorModeWrapper = { className: "ml-2" },
170
+ ctaButtonWrapper = { className: "ml-2" },
171
+ mobileMenuInner = { className: "space-y-2 px-4 pt-2 pb-4" },
172
+ mobileLinks = { className: "hover:bg-accent" },
173
+
174
+ themeToggle = {},
175
+
176
+ ariaLabel = "Main navigation",
177
+ }: NavbarProps) {
178
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
179
+ const mobileMenuId = "navbar-mobile-menu";
180
+
181
+ // Measure header height for reliable max height on mobile menu
182
+ const headerRef = useRef<HTMLDivElement | null>(null);
183
+ const [headerHeightPx, setHeaderHeightPx] = useState(0);
184
+
185
+ useEffect(() => {
186
+ const update = () =>
187
+ setHeaderHeightPx(headerRef.current?.offsetHeight ?? 0);
188
+ update();
189
+ window.addEventListener("resize", update);
190
+ return () => window.removeEventListener("resize", update);
191
+ }, []);
192
+
193
+ // Lock body scroll when mobile menu is open
194
+ useEffect(() => {
195
+ const originalOverflow = document.body.style.overflow;
196
+ if (isMobileMenuOpen) {
197
+ document.body.style.overflow = "hidden";
198
+ } else {
199
+ document.body.style.overflow = originalOverflow || "";
200
+ }
201
+ return () => {
202
+ document.body.style.overflow = originalOverflow || "";
203
+ };
204
+ }, [isMobileMenuOpen]);
205
+
206
+ return (
207
+ <nav
208
+ id={id}
209
+ className={cn(
210
+ "w-full",
211
+ sticky && "sticky top-0 z-50",
212
+ nav.className,
213
+ className,
214
+ )}
215
+ aria-label={ariaLabel}
216
+ >
217
+ <div
218
+ ref={headerRef}
219
+ className={cn(
220
+ "flex items-center justify-between px-4 py-2",
221
+ navHeight,
222
+ container.className,
223
+ )}
224
+ >
225
+ <div
226
+ className={cn(
227
+ "mr-2 flex items-center gap-2 pl-2",
228
+ brandWrapper.className,
229
+ )}
230
+ >
231
+ {brandNode}
232
+ {brand && <h1 className={cn(brandText.className)}>{brand}</h1>}
233
+ </div>
234
+
235
+ <button
236
+ aria-label="Toggle mobile menu"
237
+ aria-expanded={isMobileMenuOpen}
238
+ aria-controls={mobileMenuId}
239
+ className={cn("lg:hidden", toggleButton.className)}
240
+ // className={cn("lg:hidden", toggleButton.className)}
241
+ onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
242
+ >
243
+ {isMobileMenuOpen ? (
244
+ <X className="h-6 w-6" />
245
+ ) : (
246
+ <Menu className="h-6 w-6" />
247
+ )}
248
+ </button>
249
+
250
+ <div className={cn("hidden md:flex", desktopMenu.className)}>
251
+ {/* <div className={cn("hidden lg:flex", desktopMenu.className)}> */}
252
+ {menuItems.map((item) => (
253
+ <Link
254
+ key={item.label}
255
+ href={item.href}
256
+ className={cn(
257
+ "rounded-md px-2 py-2 transition-colors duration-200 lg:px-4",
258
+ "focus:ring-ring focus:ring-2 focus:ring-offset-2 focus:outline-none",
259
+ "focus-visible:ring-[var(--navbar-ring)]",
260
+ links.className,
261
+ )}
262
+ >
263
+ {item.label}
264
+ </Link>
265
+ ))}
266
+
267
+ {showColorModeToggle && (
268
+ <div className={cn(colorModeWrapper.className)}>
269
+ <ThemeToggle {...themeToggle} />
270
+ </div>
271
+ )}
272
+
273
+ {ctaButton && (
274
+ <Button
275
+ asChild
276
+ unstyled={ctaButtonStyle.unstyled}
277
+ variant={ctaButtonStyle.variant}
278
+ size={ctaButtonStyle.size}
279
+ className={cn(
280
+ ctaButtonWrapper.className,
281
+ ctaButtonStyle.className,
282
+ )}
283
+ style={ctaButtonStyle.style}
284
+ >
285
+ <Link href={ctaButton.href} aria-label={ctaButton.label}>
286
+ {ctaButton.label}
287
+ </Link>
288
+ </Button>
289
+ )}
290
+ </div>
291
+ </div>
292
+
293
+ {isMobileMenuOpen && (
294
+ <div
295
+ id={mobileMenuId}
296
+ className={cn(
297
+ "md:hidden",
298
+ // "lg:hidden",
299
+ "overflow-y-auto overscroll-y-contain",
300
+ nav.className,
301
+ mobileMenu.className,
302
+ )}
303
+ style={{
304
+ maxHeight: `calc(100dvh - ${headerHeightPx}px)`,
305
+ WebkitOverflowScrolling: "touch",
306
+ }}
307
+ >
308
+ <div className={cn(mobileMenuInner.className)}>
309
+ {menuItems.map((item) => (
310
+ <Link
311
+ key={item.label}
312
+ href={item.href}
313
+ className={cn(
314
+ "block w-full rounded-md px-2 py-4 text-center transition-colors duration-200",
315
+ mobileLinks.className,
316
+ "focus:ring-ring focus:ring-2 focus:ring-offset-2 focus:outline-none",
317
+ "focus-visible:ring-[var(--navbar-ring)]",
318
+ links.className,
319
+ )}
320
+ onClick={() => setIsMobileMenuOpen(false)}
321
+ >
322
+ {item.label}
323
+ </Link>
324
+ ))}
325
+
326
+ {showColorModeToggle && (
327
+ <div className="flex w-full justify-center pt-4">
328
+ <ThemeToggle {...themeToggle} />
329
+ </div>
330
+ )}
331
+
332
+ {ctaButton && (
333
+ <div className="flex w-full justify-center pt-6">
334
+ <Button
335
+ asChild
336
+ unstyled={ctaButtonStyle.unstyled}
337
+ variant={ctaButtonStyle.variant}
338
+ size={ctaButtonStyle.size}
339
+ className={cn("w-full max-w-xs", ctaButtonStyle.className)}
340
+ style={ctaButtonStyle.style}
341
+ >
342
+ <Link href={ctaButton.href} aria-label={ctaButton.label}>
343
+ {ctaButton.label}
344
+ </Link>
345
+ </Button>
346
+ </div>
347
+ )}
348
+ </div>
349
+ </div>
350
+ )}
351
+ </nav>
352
+ );
353
+ }
@@ -0,0 +1,156 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { cn } from "@/lib/utils";
5
+ import { Input } from "@/components/ui/input";
6
+ import { Button } from "@/components/ui/button";
7
+
8
+ /**
9
+ * Props for a compact newsletter/signup block.
10
+ *
11
+ * - Slot-style API (section, container, header, heading, subheading, form, formRow, input, button)
12
+ * - Merges consumer classes with sensible defaults via cn(...)
13
+ * - Uses CSS vars in defaults so token/theming overrides don't break
14
+ */
15
+ export interface NewsletterProps {
16
+ id?: string;
17
+ className?: string;
18
+
19
+ headingText?: string;
20
+ subheadingText?: string;
21
+
22
+ /** Called after successful submit (form event will be passed) */
23
+ onSubmit?: (e: React.FormEvent<HTMLFormElement>, email: string) => void;
24
+
25
+ /** Slot-style overrides */
26
+ section?: { className?: string };
27
+ container?: { className?: string };
28
+ header?: { className?: string };
29
+ heading?: { className?: string };
30
+ subheading?: { className?: string };
31
+ form?: { className?: string };
32
+ formRow?: { className?: string };
33
+ input?: { className?: string };
34
+ button?: {
35
+ className?: string;
36
+ variant?: any;
37
+ size?: any;
38
+ unstyled?: boolean;
39
+ };
40
+
41
+ enableMotion?: boolean;
42
+
43
+ ariaLabel?: string;
44
+ }
45
+
46
+ // Default classes used for slot merging. Consumers' slot.className will be merged after these.
47
+ const DEFAULT_SECTION = "py-12 bg-[var(--card-bg)] text-[var(--card-fg)]";
48
+ const DEFAULT_CONTAINER = "max-w-3xl mx-auto px-4";
49
+ const DEFAULT_HEADER = "text-center mb-6";
50
+ const DEFAULT_HEADING =
51
+ "text-2xl font-bold font-poppins text-foreground text-[var(--heading-fg)]";
52
+ const DEFAULT_SUBHEADING =
53
+ "text-sm font-inter text-muted-foreground max-w-xl mx-auto leading-relaxed text-[var(--subheading-fg)]";
54
+ const DEFAULT_FORM = "w-full";
55
+ const DEFAULT_FORM_ROW =
56
+ "mt-6 flex flex-col sm:flex-row items-center gap-3 justify-center";
57
+ const DEFAULT_INPUT =
58
+ "w-full sm:flex-1 p-3 rounded-md border border-[var(--input-border)] bg-[var(--input-bg)] text-[var(--input-fg)] placeholder:text-[var(--input-placeholder)]";
59
+ const DEFAULT_BUTTON =
60
+ "w-full sm:w-auto px-5 py-3 rounded-md bg-primary hover:bg-primary/90 dark:bg-primary dark:hover:bg-primary text-primary-foreground font-medium shadow-lg hover:shadow-xl transition-all duration-200 hover:-translate-y-0.5 border-[var(--btn-border)] focus-visible:ring-[var(--btn-ring)]";
61
+
62
+ /**
63
+ * Compact newsletter/signup block.
64
+ *
65
+ * Usage:
66
+ * <Newsletter section={{ className: "bg-gradient-to-r ..." }} />
67
+ *
68
+ * Slots exposed: section, container, header, heading, subheading, form, formRow, input, button
69
+ */
70
+ export function Newsletter({
71
+ id,
72
+ className,
73
+ headingText = "Stay in the loop",
74
+ subheadingText = "Subscribe for product news, tips, and updates.",
75
+ onSubmit,
76
+ section,
77
+ container,
78
+ header,
79
+ heading,
80
+ subheading,
81
+ form,
82
+ formRow,
83
+ input,
84
+ button,
85
+ enableMotion = true,
86
+ ariaLabel = "Newsletter signup section",
87
+ }: NewsletterProps) {
88
+ const [email, setEmail] = React.useState("");
89
+ const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
90
+ e.preventDefault();
91
+ onSubmit?.(e, email);
92
+ // Optimistic clear; consumer can override behavior via onSubmit
93
+ setEmail("");
94
+ };
95
+
96
+ return (
97
+ <section
98
+ id={id}
99
+ className={cn(DEFAULT_SECTION, section?.className, className)}
100
+ aria-label={ariaLabel}
101
+ >
102
+ <div className={cn(DEFAULT_CONTAINER, container?.className)}>
103
+ <div className={cn(DEFAULT_HEADER, header?.className)}>
104
+ <h2 className={cn(DEFAULT_HEADING, heading?.className)}>
105
+ {headingText}
106
+ </h2>
107
+ <p className={cn(DEFAULT_SUBHEADING, subheading?.className)}>
108
+ {subheadingText}
109
+ </p>
110
+ </div>
111
+
112
+ <form
113
+ className={cn(DEFAULT_FORM, form?.className)}
114
+ onSubmit={handleSubmit}
115
+ aria-label="Newsletter signup form"
116
+ >
117
+ <div className={cn(DEFAULT_FORM_ROW, formRow?.className)}>
118
+ <Input
119
+ id="newsletter-email"
120
+ name="email"
121
+ type="email"
122
+ value={email}
123
+ onChange={(e) => setEmail(e.target.value)}
124
+ placeholder="Your email address"
125
+ required
126
+ aria-label="Email address"
127
+ className={cn(DEFAULT_INPUT, input?.className)}
128
+ />
129
+
130
+ <Button
131
+ type="submit"
132
+ unstyled={button?.unstyled}
133
+ variant={button?.variant}
134
+ size={button?.size}
135
+ className={cn(
136
+ DEFAULT_BUTTON,
137
+ button?.className,
138
+ !enableMotion &&
139
+ "transition-none hover:!translate-y-0 hover:shadow-none",
140
+ )}
141
+ >
142
+ Subscribe
143
+ </Button>
144
+ </div>
145
+ </form>
146
+ </div>
147
+ </section>
148
+ );
149
+ }
150
+
151
+ /*
152
+ Example component summary:
153
+ - Slots exposed: section, container, header, heading, subheading, form, formRow, input, button
154
+ - Accessibility: aria-label defaults; form has aria-label; input has aria-label; uses semantic <section>
155
+ - Motion: enableMotion prop implemented (removes hover/transition classes when false)
156
+ */