@nextsparkjs/core 0.1.0-beta.188 → 0.1.0-beta.189

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 (412) hide show
  1. package/dist/components/api/keys/ApiKeyDisplay.js +19 -19
  2. package/dist/components/api/keys/CreateApiKeyDialog.js +21 -21
  3. package/dist/components/app/layouts/PublicNavbar.d.ts.map +1 -1
  4. package/dist/components/app/layouts/PublicNavbar.js +34 -16
  5. package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
  6. package/dist/components/app/misc/ThemeToggle.js +3 -4
  7. package/dist/components/auth/SessionCookieRefresher.d.ts +5 -0
  8. package/dist/components/auth/SessionCookieRefresher.d.ts.map +1 -1
  9. package/dist/components/auth/SessionCookieRefresher.js +7 -1
  10. package/dist/components/auth/forms/LoginForm.d.ts.map +1 -1
  11. package/dist/components/auth/forms/LoginForm.js +49 -12
  12. package/dist/components/auth/forms/SignupForm.d.ts.map +1 -1
  13. package/dist/components/auth/forms/SignupForm.js +4 -3
  14. package/dist/components/dashboard/block-editor/block-settings-panel.js +1 -1
  15. package/dist/components/dashboard/block-editor/floating-block-toolbar.js +1 -1
  16. package/dist/components/dashboard/block-editor/sortable-block.js +1 -1
  17. package/dist/components/dashboard/layouts/Sidebar.d.ts.map +1 -1
  18. package/dist/components/dashboard/layouts/Sidebar.js +8 -6
  19. package/dist/components/dashboard/layouts/TopNavbar.d.ts.map +1 -1
  20. package/dist/components/dashboard/layouts/TopNavbar.js +51 -54
  21. package/dist/components/dashboard/misc/NotificationsDropdown.d.ts.map +1 -1
  22. package/dist/components/dashboard/misc/NotificationsDropdown.js +17 -15
  23. package/dist/components/dashboard/misc/SearchDropdown.d.ts.map +1 -1
  24. package/dist/components/dashboard/misc/SearchDropdown.js +19 -22
  25. package/dist/components/dashboard/mobile/MobileBottomNav.js +1 -1
  26. package/dist/components/dashboard/mobile/MobileTopBar.js +2 -2
  27. package/dist/components/dashboard/navigation/DynamicNavigation.js +5 -5
  28. package/dist/components/devtools/BlockDetailViewer.js +1 -1
  29. package/dist/components/devtools/BlocksViewer.js +1 -1
  30. package/dist/components/entities/EntityChildManager.js +5 -5
  31. package/dist/components/entities/EntityDetailPage.d.ts.map +1 -1
  32. package/dist/components/entities/EntityDetailPage.js +16 -15
  33. package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
  34. package/dist/components/entities/EntityFieldRenderer.js +12 -7
  35. package/dist/components/entities/EntityPageHeader.js +5 -5
  36. package/dist/components/entities/ErrorBoundary.d.ts.map +1 -1
  37. package/dist/components/entities/ErrorBoundary.js +20 -21
  38. package/dist/components/entities/wrappers/EntityDetailWrapper.js +5 -5
  39. package/dist/components/entities/wrappers/EntityFormWrapper.js +2 -2
  40. package/dist/components/entities/wrappers/EntityListWrapper.js +3 -3
  41. package/dist/components/permissions/NoPermission.js +10 -10
  42. package/dist/components/public/pageBuilder/PageRenderer.d.ts.map +1 -1
  43. package/dist/components/public/pageBuilder/PageRenderer.js +2 -1
  44. package/dist/components/settings/SettingsPageSkeleton.js +4 -4
  45. package/dist/components/settings/layouts/SettingsSidebar.js +6 -6
  46. package/dist/components/shared/MultiSelectFilter.d.ts +3 -1
  47. package/dist/components/shared/MultiSelectFilter.d.ts.map +1 -1
  48. package/dist/components/shared/MultiSelectFilter.js +7 -3
  49. package/dist/components/shared/SearchInput.d.ts +2 -0
  50. package/dist/components/shared/SearchInput.d.ts.map +1 -1
  51. package/dist/components/shared/SearchInput.js +64 -6
  52. package/dist/components/ui/address-input.js +18 -18
  53. package/dist/components/ui/audio-upload.js +9 -9
  54. package/dist/components/ui/combobox.d.ts.map +1 -1
  55. package/dist/components/ui/combobox.js +4 -4
  56. package/dist/components/ui/country-select.d.ts.map +1 -1
  57. package/dist/components/ui/country-select.js +3 -3
  58. package/dist/components/ui/currency-select.d.ts.map +1 -1
  59. package/dist/components/ui/currency-select.js +3 -3
  60. package/dist/components/ui/dynamic-icon.d.ts.map +1 -1
  61. package/dist/components/ui/dynamic-icon.js +3 -2
  62. package/dist/components/ui/file-upload.js +7 -7
  63. package/dist/components/ui/image-upload.js +8 -8
  64. package/dist/components/ui/multi-select.d.ts +2 -1
  65. package/dist/components/ui/multi-select.d.ts.map +1 -1
  66. package/dist/components/ui/multi-select.js +4 -3
  67. package/dist/components/ui/phone-input.d.ts.map +1 -1
  68. package/dist/components/ui/phone-input.js +3 -3
  69. package/dist/components/ui/relation-display.js +1 -1
  70. package/dist/components/ui/simple-relation-select.d.ts +2 -1
  71. package/dist/components/ui/simple-relation-select.d.ts.map +1 -1
  72. package/dist/components/ui/simple-relation-select.js +7 -6
  73. package/dist/components/ui/tags-input.d.ts.map +1 -1
  74. package/dist/components/ui/tags-input.js +1 -1
  75. package/dist/components/ui/timezone-select.d.ts.map +1 -1
  76. package/dist/components/ui/timezone-select.js +3 -3
  77. package/dist/components/ui/user-display.js +4 -4
  78. package/dist/components/ui/user-select.d.ts.map +1 -1
  79. package/dist/components/ui/user-select.js +9 -9
  80. package/dist/components/ui/video-upload.js +9 -9
  81. package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
  82. package/dist/contexts/SubscriptionContext.js +5 -1
  83. package/dist/contexts/TeamContext.d.ts.map +1 -1
  84. package/dist/contexts/TeamContext.js +83 -26
  85. package/dist/emails/otp-verification.d.ts.map +1 -1
  86. package/dist/emails/otp-verification.js +3 -2
  87. package/dist/hooks/useAccountPreferencesSync.d.ts +13 -0
  88. package/dist/hooks/useAccountPreferencesSync.d.ts.map +1 -0
  89. package/dist/hooks/useAccountPreferencesSync.js +95 -0
  90. package/dist/hooks/useAuth.d.ts +202 -15
  91. package/dist/hooks/useAuth.d.ts.map +1 -1
  92. package/dist/hooks/useAuth.js +49 -13
  93. package/dist/hooks/useEntityConfig.js +2 -2
  94. package/dist/hooks/useEntitySearch.js +10 -10
  95. package/dist/hooks/useNotifications.js +12 -12
  96. package/dist/hooks/usePrefetch.d.ts.map +1 -1
  97. package/dist/hooks/usePrefetch.js +6 -2
  98. package/dist/hooks/useSearch.js +15 -15
  99. package/dist/hooks/useSessionCookieRefresh.d.ts +18 -1
  100. package/dist/hooks/useSessionCookieRefresh.d.ts.map +1 -1
  101. package/dist/hooks/useSessionCookieRefresh.js +17 -4
  102. package/dist/hooks/useSessionHint.d.ts +12 -0
  103. package/dist/hooks/useSessionHint.d.ts.map +1 -0
  104. package/dist/hooks/useSessionHint.js +15 -0
  105. package/dist/hooks/useTranslationPreload.js +6 -6
  106. package/dist/i18n.d.ts +13 -0
  107. package/dist/i18n.d.ts.map +1 -1
  108. package/dist/i18n.js +2 -27
  109. package/dist/lib/actions/entity.actions.d.ts.map +1 -1
  110. package/dist/lib/actions/entity.actions.js +3 -2
  111. package/dist/lib/api/auth/dual-auth.d.ts +4 -1
  112. package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
  113. package/dist/lib/api/auth/dual-auth.js +5 -16
  114. package/dist/lib/api/entities.js +33 -33
  115. package/dist/lib/api/keys.d.ts +27 -27
  116. package/dist/lib/api/keys.js +27 -27
  117. package/dist/lib/auth/callback-url.d.ts +11 -0
  118. package/dist/lib/auth/callback-url.d.ts.map +1 -0
  119. package/dist/lib/auth/callback-url.js +14 -0
  120. package/dist/lib/auth/otp-config.d.ts +55 -0
  121. package/dist/lib/auth/otp-config.d.ts.map +1 -0
  122. package/dist/lib/auth/otp-config.js +48 -0
  123. package/dist/lib/auth/registration-helpers.d.ts.map +1 -1
  124. package/dist/lib/auth/registration-helpers.js +3 -1
  125. package/dist/lib/auth/session-hint.d.ts +31 -0
  126. package/dist/lib/auth/session-hint.d.ts.map +1 -0
  127. package/dist/lib/auth/session-hint.js +37 -0
  128. package/dist/lib/auth.d.ts.map +1 -1
  129. package/dist/lib/auth.js +6 -4
  130. package/dist/lib/blocks/loader.d.ts +3 -11
  131. package/dist/lib/blocks/loader.d.ts.map +1 -1
  132. package/dist/lib/blocks/loader.js +1 -9
  133. package/dist/lib/blocks/loader.server.d.ts +18 -0
  134. package/dist/lib/blocks/loader.server.d.ts.map +1 -0
  135. package/dist/lib/blocks/loader.server.js +11 -0
  136. package/dist/lib/blocks/sanitize-html.d.ts +31 -0
  137. package/dist/lib/blocks/sanitize-html.d.ts.map +1 -0
  138. package/dist/lib/blocks/sanitize-html.js +60 -0
  139. package/dist/lib/config/config-sync.d.ts +1 -0
  140. package/dist/lib/config/config-sync.d.ts.map +1 -1
  141. package/dist/lib/config/config-sync.js +4 -1
  142. package/dist/lib/config/types.d.ts +48 -0
  143. package/dist/lib/config/types.d.ts.map +1 -1
  144. package/dist/lib/email/types.d.ts +6 -0
  145. package/dist/lib/email/types.d.ts.map +1 -1
  146. package/dist/lib/entities/serialization.d.ts.map +1 -1
  147. package/dist/lib/entities/serialization.js +3 -6
  148. package/dist/lib/icons.d.ts +12 -0
  149. package/dist/lib/icons.d.ts.map +1 -0
  150. package/dist/lib/icons.js +30 -0
  151. package/dist/lib/locale.d.ts +25 -1
  152. package/dist/lib/locale.d.ts.map +1 -1
  153. package/dist/lib/locale.js +49 -35
  154. package/dist/lib/mcp/engine.js +1 -1
  155. package/dist/lib/mcp/errors.js +17 -17
  156. package/dist/lib/mcp/schema-builder.js +16 -16
  157. package/dist/lib/mcp/tool-generator.js +18 -18
  158. package/dist/lib/search-highlighting.d.ts +7 -0
  159. package/dist/lib/search-highlighting.d.ts.map +1 -1
  160. package/dist/lib/search-highlighting.js +6 -2
  161. package/dist/lib/selectors/core-selectors.d.ts +2 -0
  162. package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
  163. package/dist/lib/selectors/domains/auth.selectors.d.ts +1 -0
  164. package/dist/lib/selectors/domains/auth.selectors.d.ts.map +1 -1
  165. package/dist/lib/selectors/domains/auth.selectors.js +1 -0
  166. package/dist/lib/selectors/domains/entities.selectors.d.ts +2 -0
  167. package/dist/lib/selectors/domains/entities.selectors.d.ts.map +1 -1
  168. package/dist/lib/selectors/domains/entities.selectors.js +2 -0
  169. package/dist/lib/selectors/selectors.d.ts +4 -0
  170. package/dist/lib/selectors/selectors.d.ts.map +1 -1
  171. package/dist/lib/services/block.service.js +1 -1
  172. package/dist/lib/teams/active-team-cookie.d.ts +24 -0
  173. package/dist/lib/teams/active-team-cookie.d.ts.map +1 -0
  174. package/dist/lib/teams/active-team-cookie.js +17 -0
  175. package/dist/lib/teams/dashboard-team.d.ts +20 -0
  176. package/dist/lib/teams/dashboard-team.d.ts.map +1 -0
  177. package/dist/lib/teams/dashboard-team.js +38 -0
  178. package/dist/lib/teams/schema.d.ts.map +1 -1
  179. package/dist/lib/teams/schema.js +1 -1
  180. package/dist/lib/template-resolver.d.ts.map +1 -1
  181. package/dist/lib/template-resolver.js +0 -1
  182. package/dist/lib/theme/get-default-theme-mode.d.ts +7 -4
  183. package/dist/lib/theme/get-default-theme-mode.d.ts.map +1 -1
  184. package/dist/lib/theme/get-default-theme-mode.js +2 -44
  185. package/dist/messages/de/auth.json +4 -2
  186. package/dist/messages/de/common.json +83 -3
  187. package/dist/messages/de/email.json +1 -1
  188. package/dist/messages/de/index.d.ts +87 -0
  189. package/dist/messages/de/index.d.ts.map +1 -1
  190. package/dist/messages/de/settings.json +5 -0
  191. package/dist/messages/en/auth.json +4 -2
  192. package/dist/messages/en/common.json +83 -3
  193. package/dist/messages/en/email.json +1 -1
  194. package/dist/messages/en/index.d.ts +86 -0
  195. package/dist/messages/en/index.d.ts.map +1 -1
  196. package/dist/messages/en/settings.json +4 -0
  197. package/dist/messages/es/auth.json +4 -2
  198. package/dist/messages/es/common.json +83 -3
  199. package/dist/messages/es/email.json +1 -1
  200. package/dist/messages/es/index.d.ts +86 -0
  201. package/dist/messages/es/index.d.ts.map +1 -1
  202. package/dist/messages/es/settings.json +4 -0
  203. package/dist/messages/fr/auth.json +4 -2
  204. package/dist/messages/fr/common.json +83 -3
  205. package/dist/messages/fr/email.json +1 -1
  206. package/dist/messages/fr/index.d.ts +87 -0
  207. package/dist/messages/fr/index.d.ts.map +1 -1
  208. package/dist/messages/fr/settings.json +5 -0
  209. package/dist/messages/it/auth.json +4 -2
  210. package/dist/messages/it/common.json +83 -3
  211. package/dist/messages/it/email.json +1 -1
  212. package/dist/messages/it/index.d.ts +87 -0
  213. package/dist/messages/it/index.d.ts.map +1 -1
  214. package/dist/messages/it/settings.json +5 -0
  215. package/dist/messages/pt/auth.json +4 -2
  216. package/dist/messages/pt/common.json +83 -3
  217. package/dist/messages/pt/email.json +1 -1
  218. package/dist/messages/pt/index.d.ts +87 -0
  219. package/dist/messages/pt/index.d.ts.map +1 -1
  220. package/dist/messages/pt/settings.json +5 -0
  221. package/dist/nextspark-registries.d.ts +54 -0
  222. package/dist/providers/DashboardProviders.d.ts +13 -10
  223. package/dist/providers/DashboardProviders.d.ts.map +1 -1
  224. package/dist/providers/DashboardProviders.js +7 -1
  225. package/dist/templates/app/(auth)/forgot-password/page.tsx +2 -2
  226. package/dist/templates/app/(auth)/reset-password/page.tsx +6 -6
  227. package/dist/templates/app/403/page.tsx +6 -6
  228. package/dist/templates/app/api/v1/teams/switch/route.ts +24 -5
  229. package/dist/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
  230. package/dist/templates/app/dashboard/(main)/layout.tsx +4 -3
  231. package/dist/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
  232. package/dist/templates/app/dashboard/settings/profile/page.tsx +7 -6
  233. package/dist/templates/app/dashboard/settings/security/page.tsx +5 -4
  234. package/dist/templates/app/layout.ppr.tsx +8 -8
  235. package/dist/templates/app/layout.tsx +12 -17
  236. package/dist/templates/blocks/cta-section/component.tsx +5 -2
  237. package/dist/templates/blocks/cta-section/config.ts +3 -2
  238. package/dist/templates/blocks/cta-section/fields.ts +2 -2
  239. package/dist/templates/blocks/cta-section/schema.ts +2 -2
  240. package/dist/templates/blocks/features-grid/component.tsx +10 -2
  241. package/dist/templates/blocks/features-grid/config.ts +3 -2
  242. package/dist/templates/blocks/features-grid/fields.ts +2 -2
  243. package/dist/templates/blocks/features-grid/schema.ts +2 -2
  244. package/dist/templates/blocks/hero/component.tsx +6 -3
  245. package/dist/templates/blocks/hero/config.ts +3 -2
  246. package/dist/templates/blocks/hero/fields.ts +2 -2
  247. package/dist/templates/blocks/hero/schema.ts +2 -2
  248. package/dist/templates/blocks/testimonials/component.tsx +6 -3
  249. package/dist/templates/blocks/testimonials/config.ts +3 -2
  250. package/dist/templates/blocks/testimonials/fields.ts +2 -2
  251. package/dist/templates/blocks/testimonials/schema.ts +2 -2
  252. package/dist/templates/blocks/text-content/component.tsx +7 -3
  253. package/dist/templates/blocks/text-content/config.ts +3 -2
  254. package/dist/templates/blocks/text-content/fields.ts +2 -2
  255. package/dist/templates/blocks/text-content/schema.ts +2 -2
  256. package/dist/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
  257. package/dist/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
  258. package/dist/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
  259. package/dist/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
  260. package/dist/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
  261. package/dist/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
  262. package/dist/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
  263. package/dist/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
  264. package/dist/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
  265. package/dist/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
  266. package/dist/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
  267. package/dist/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
  268. package/dist/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
  269. package/dist/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
  270. package/dist/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
  271. package/dist/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
  272. package/dist/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
  273. package/dist/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
  274. package/dist/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
  275. package/dist/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
  276. package/dist/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
  277. package/dist/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
  278. package/dist/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
  279. package/dist/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
  280. package/dist/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
  281. package/dist/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
  282. package/dist/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
  283. package/dist/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
  284. package/dist/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
  285. package/dist/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
  286. package/dist/templates/contents/themes/starter/config/app.config.ts +8 -0
  287. package/dist/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
  288. package/dist/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
  289. package/dist/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
  290. package/dist/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
  291. package/dist/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
  292. package/dist/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
  293. package/dist/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
  294. package/dist/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
  295. package/dist/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
  296. package/dist/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
  297. package/dist/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
  298. package/dist/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
  299. package/dist/templates/features/blog/blocks/post-content/component.tsx +5 -1
  300. package/dist/templates/features/blog/blocks/post-content/schema.ts +1 -1
  301. package/dist/templates/features/pages/blocks/hero/component.tsx +3 -0
  302. package/dist/templates/features/pages/blocks/hero/schema.ts +1 -1
  303. package/dist/templates/proxy.ts +138 -53
  304. package/dist/types/blocks.d.ts.map +1 -1
  305. package/dist/types/blocks.js +1 -1
  306. package/dist/types/task.types.d.ts +1 -1
  307. package/dist/types/task.types.js +7 -7
  308. package/dist/utils/dev/TranslationDebugger.js +2 -2
  309. package/package.json +14 -5
  310. package/scripts/build/registry/__tests__/block-registry.test.mjs +73 -0
  311. package/scripts/build/registry/__tests__/icons-discovery.test.mjs +130 -0
  312. package/scripts/build/registry/__tests__/identifier.test.mjs +65 -0
  313. package/scripts/build/registry/__tests__/page-generator.test.mjs +430 -0
  314. package/scripts/build/registry/__tests__/scheduled-actions-registry.test.mjs +41 -0
  315. package/scripts/build/registry/__tests__/template-registry.test.mjs +89 -0
  316. package/scripts/build/registry/discovery/icons.mjs +275 -0
  317. package/scripts/build/registry/discovery/index.mjs +1 -0
  318. package/scripts/build/registry/generators/block-registry.mjs +203 -55
  319. package/scripts/build/registry/generators/feature-registry.mjs +9 -2
  320. package/scripts/build/registry/generators/icon-registry.mjs +56 -0
  321. package/scripts/build/registry/generators/identifier.mjs +28 -0
  322. package/scripts/build/registry/generators/index.mjs +1 -0
  323. package/scripts/build/registry/generators/plugin-registry.mjs +4 -3
  324. package/scripts/build/registry/generators/scheduled-actions-registry.mjs +4 -2
  325. package/scripts/build/registry/generators/template-registry.mjs +49 -41
  326. package/scripts/build/registry/generators/theme-registry.mjs +6 -7
  327. package/scripts/build/registry/post-build/page-generator.mjs +380 -59
  328. package/scripts/build/registry.mjs +9 -1
  329. package/templates/app/(auth)/forgot-password/page.tsx +2 -2
  330. package/templates/app/(auth)/reset-password/page.tsx +6 -6
  331. package/templates/app/403/page.tsx +6 -6
  332. package/templates/app/api/v1/teams/switch/route.ts +24 -5
  333. package/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
  334. package/templates/app/dashboard/(main)/layout.tsx +4 -3
  335. package/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
  336. package/templates/app/dashboard/settings/profile/page.tsx +7 -6
  337. package/templates/app/dashboard/settings/security/page.tsx +5 -4
  338. package/templates/app/layout.ppr.tsx +8 -8
  339. package/templates/app/layout.tsx +12 -17
  340. package/templates/blocks/cta-section/component.tsx +5 -2
  341. package/templates/blocks/cta-section/config.ts +3 -2
  342. package/templates/blocks/cta-section/fields.ts +2 -2
  343. package/templates/blocks/cta-section/schema.ts +2 -2
  344. package/templates/blocks/features-grid/component.tsx +10 -2
  345. package/templates/blocks/features-grid/config.ts +3 -2
  346. package/templates/blocks/features-grid/fields.ts +2 -2
  347. package/templates/blocks/features-grid/schema.ts +2 -2
  348. package/templates/blocks/hero/component.tsx +6 -3
  349. package/templates/blocks/hero/config.ts +3 -2
  350. package/templates/blocks/hero/fields.ts +2 -2
  351. package/templates/blocks/hero/schema.ts +2 -2
  352. package/templates/blocks/testimonials/component.tsx +6 -3
  353. package/templates/blocks/testimonials/config.ts +3 -2
  354. package/templates/blocks/testimonials/fields.ts +2 -2
  355. package/templates/blocks/testimonials/schema.ts +2 -2
  356. package/templates/blocks/text-content/component.tsx +7 -3
  357. package/templates/blocks/text-content/config.ts +3 -2
  358. package/templates/blocks/text-content/fields.ts +2 -2
  359. package/templates/blocks/text-content/schema.ts +2 -2
  360. package/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
  361. package/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
  362. package/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
  363. package/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
  364. package/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
  365. package/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
  366. package/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
  367. package/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
  368. package/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
  369. package/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
  370. package/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
  371. package/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
  372. package/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
  373. package/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
  374. package/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
  375. package/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
  376. package/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
  377. package/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
  378. package/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
  379. package/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
  380. package/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
  381. package/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
  382. package/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
  383. package/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
  384. package/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
  385. package/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
  386. package/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
  387. package/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
  388. package/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
  389. package/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
  390. package/templates/contents/themes/starter/config/app.config.ts +8 -0
  391. package/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
  392. package/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
  393. package/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
  394. package/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
  395. package/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
  396. package/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
  397. package/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
  398. package/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
  399. package/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
  400. package/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
  401. package/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
  402. package/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
  403. package/templates/features/blog/blocks/post-content/component.tsx +5 -1
  404. package/templates/features/blog/blocks/post-content/schema.ts +1 -1
  405. package/templates/features/pages/blocks/hero/component.tsx +3 -0
  406. package/templates/features/pages/blocks/hero/schema.ts +1 -1
  407. package/templates/proxy.ts +138 -53
  408. package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.client.ts +9 -0
  409. package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.lazy.ts +5 -0
  410. package/tests/jest/__mocks__/@nextsparkjs/registries/icon-registry.ts +42 -0
  411. package/tests/jest/__mocks__/next-intl-server.js +85 -5
  412. package/tests/jest/__mocks__/next-server.js +32 -0
@@ -1,4 +1,4 @@
1
- import type { BlockConfig } from '@/core/types/blocks'
1
+ import type { BlockConfig } from '@nextsparkjs/core/types/blocks'
2
2
 
3
3
  export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Component' | 'examples'> = {
4
4
  slug: 'testimonials',
@@ -6,5 +6,6 @@ export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Componen
6
6
  description: 'Display customer testimonials with quotes, authors, and avatars',
7
7
  category: 'testimonials',
8
8
  icon: 'Quote',
9
- thumbnail: '/theme/blocks/testimonials/thumbnail.png'
9
+ thumbnail: '/theme/blocks/testimonials/thumbnail.png',
10
+ scope: ['pages']
10
11
  }
@@ -1,9 +1,9 @@
1
- import type { FieldDefinition } from '@/core/types/blocks'
1
+ import type { FieldDefinition } from '@nextsparkjs/core/types/blocks'
2
2
  import {
3
3
  baseContentFields,
4
4
  baseDesignFields,
5
5
  baseAdvancedFields,
6
- } from '@/core/types/blocks'
6
+ } from '@nextsparkjs/core/types/blocks'
7
7
 
8
8
  /**
9
9
  * Testimonials Block Field Definitions
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod'
2
- import { baseBlockSchema, mediaRefSchema } from '@/core/types/blocks'
2
+ import { baseBlockSchema, mediaRefSchema } from '@nextsparkjs/core/types/blocks'
3
3
 
4
4
  /**
5
5
  * Testimonial Item Schema
@@ -36,6 +36,6 @@ export const testimonialsSpecificSchema = z.object({
36
36
  /**
37
37
  * Complete Testimonials Block Schema
38
38
  */
39
- export const schema = baseBlockSchema.merge(testimonialsSpecificSchema)
39
+ export const schema = baseBlockSchema.extend(testimonialsSpecificSchema.shape)
40
40
 
41
41
  export type TestimonialsBlockProps = z.infer<typeof schema>
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
- import { cn } from '@/core/lib/utils'
3
- import { buildSectionClasses } from '@/core/types/blocks'
2
+ import { cn } from '@nextsparkjs/core/lib/utils'
3
+ import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
4
+ import { sanitizeBlockHtml } from '@nextsparkjs/core/lib/blocks/sanitize-html'
4
5
  import type { TextContentBlockProps } from './schema'
5
6
 
6
7
  /**
@@ -70,7 +71,7 @@ export function TextContentBlock({
70
71
  maxWidthClasses[maxWidth],
71
72
  alignmentClasses[alignment]
72
73
  )}
73
- dangerouslySetInnerHTML={{ __html: content }}
74
+ dangerouslySetInnerHTML={{ __html: sanitizeBlockHtml(content) }}
74
75
  />
75
76
 
76
77
  {/* Optional CTA */}
@@ -94,3 +95,6 @@ export function TextContentBlock({
94
95
  </section>
95
96
  )
96
97
  }
98
+
99
+ // The generated block registry imports this as the module's default.
100
+ export default TextContentBlock
@@ -1,4 +1,4 @@
1
- import type { BlockConfig } from '@/core/types/blocks'
1
+ import type { BlockConfig } from '@nextsparkjs/core/types/blocks'
2
2
 
3
3
  export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Component' | 'examples'> = {
4
4
  slug: 'text-content',
@@ -6,5 +6,6 @@ export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Componen
6
6
  description: 'Rich text content block for paragraphs, lists, and formatted text',
7
7
  category: 'content',
8
8
  icon: 'FileText',
9
- thumbnail: '/theme/blocks/text-content/thumbnail.png'
9
+ thumbnail: '/theme/blocks/text-content/thumbnail.png',
10
+ scope: ['pages']
10
11
  }
@@ -1,9 +1,9 @@
1
- import type { FieldDefinition } from '@/core/types/blocks'
1
+ import type { FieldDefinition } from '@nextsparkjs/core/types/blocks'
2
2
  import {
3
3
  baseContentFields,
4
4
  baseDesignFields,
5
5
  baseAdvancedFields,
6
- } from '@/core/types/blocks'
6
+ } from '@nextsparkjs/core/types/blocks'
7
7
 
8
8
  /**
9
9
  * Text Content Block Field Definitions
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod'
2
- import { baseBlockSchema } from '@/core/types/blocks'
2
+ import { baseBlockSchema } from '@nextsparkjs/core/types/blocks'
3
3
 
4
4
  /**
5
5
  * Text Content Block Schema
@@ -25,6 +25,6 @@ export const textContentSpecificSchema = z.object({
25
25
  * Complete Text Content Block Schema
26
26
  * Note: textContentSpecificSchema.content overrides baseBlockSchema.content
27
27
  */
28
- export const schema = baseBlockSchema.merge(textContentSpecificSchema)
28
+ export const schema = baseBlockSchema.extend(textContentSpecificSchema.shape)
29
29
 
30
30
  export type TextContentBlockProps = z.infer<typeof schema>
@@ -0,0 +1,102 @@
1
+ import React from 'react'
2
+ import { Button } from '@nextsparkjs/core/components/ui/button'
3
+ import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
4
+ import type { CTASectionBlockProps } from './schema'
5
+
6
+ /**
7
+ * CTA Section Block Component
8
+ *
9
+ * Props from 3-tab structure:
10
+ * - Content: title, content, cta (primary), secondaryButton
11
+ * - Design: backgroundColor
12
+ * - Advanced: className, id
13
+ */
14
+ export function CTASectionBlock({
15
+ // Base content props
16
+ title,
17
+ content,
18
+ cta,
19
+ // CTA-specific content
20
+ secondaryButton,
21
+ // Base design props
22
+ backgroundColor,
23
+ // Base advanced props
24
+ className,
25
+ id,
26
+ // Legacy props for backward compatibility
27
+ ...legacyProps
28
+ }: CTASectionBlockProps & {
29
+ buttonText?: string
30
+ buttonLink?: string
31
+ primaryButton?: { text: string; link: string; variant?: string }
32
+ description?: string
33
+ }) {
34
+ // Handle legacy format (buttonText/buttonLink or primaryButton)
35
+ const primaryCta = cta || (legacyProps.primaryButton ? {
36
+ text: legacyProps.primaryButton.text,
37
+ link: legacyProps.primaryButton.link,
38
+ target: '_self' as const,
39
+ } : legacyProps.buttonText ? {
40
+ text: legacyProps.buttonText,
41
+ link: legacyProps.buttonLink || '#',
42
+ target: '_self' as const,
43
+ } : undefined)
44
+
45
+ // Handle legacy description prop
46
+ const displayContent = content || (legacyProps as { description?: string }).description
47
+
48
+ // Build section classes with background and custom className
49
+ const sectionClasses = buildSectionClasses(
50
+ 'py-16 px-4 @md:py-24',
51
+ { backgroundColor, className }
52
+ )
53
+
54
+ return (
55
+ <section id={id} className={sectionClasses} data-cy="block-cta-section">
56
+ <div className="container mx-auto max-w-4xl text-center">
57
+ {title && (
58
+ <h2 className="mb-4 text-4xl font-bold @md:text-5xl">{title}</h2>
59
+ )}
60
+
61
+ {displayContent && (
62
+ <p className="mb-8 text-lg @md:text-xl opacity-90">{displayContent}</p>
63
+ )}
64
+
65
+ {(primaryCta || secondaryButton) && (
66
+ <div className="flex flex-col gap-4 @sm:flex-row @sm:justify-center">
67
+ {primaryCta && (
68
+ <Button asChild size="lg">
69
+ <a
70
+ href={primaryCta.link}
71
+ target={primaryCta.target}
72
+ rel={primaryCta.target === '_blank' ? 'noopener noreferrer' : undefined}
73
+ >
74
+ {primaryCta.text}
75
+ </a>
76
+ </Button>
77
+ )}
78
+
79
+ {secondaryButton && (
80
+ <Button
81
+ asChild
82
+ size="lg"
83
+ variant={secondaryButton.variant || 'outline'}
84
+ >
85
+ <a
86
+ href={secondaryButton.link}
87
+ target={secondaryButton.target}
88
+ rel={secondaryButton.target === '_blank' ? 'noopener noreferrer' : undefined}
89
+ >
90
+ {secondaryButton.text}
91
+ </a>
92
+ </Button>
93
+ )}
94
+ </div>
95
+ )}
96
+ </div>
97
+ </section>
98
+ )
99
+ }
100
+
101
+ // The generated block registry imports this as the module's default.
102
+ export default CTASectionBlock
@@ -0,0 +1,11 @@
1
+ import type { BlockConfig } from '@nextsparkjs/core/types/blocks'
2
+
3
+ export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Component' | 'examples'> = {
4
+ slug: 'cta-section',
5
+ name: 'CTA Section',
6
+ description: 'Call-to-action section with title, description, and action buttons',
7
+ category: 'cta',
8
+ icon: 'Megaphone',
9
+ thumbnail: '/theme/blocks/cta-section/thumbnail.png',
10
+ scope: ['pages']
11
+ }
@@ -0,0 +1,89 @@
1
+ import type { FieldDefinition } from '@nextsparkjs/core/types/blocks'
2
+ import {
3
+ baseContentFields,
4
+ baseDesignFields,
5
+ baseAdvancedFields,
6
+ } from '@nextsparkjs/core/types/blocks'
7
+
8
+ /**
9
+ * CTA Section Block Field Definitions
10
+ *
11
+ * Organized into 3 tabs:
12
+ * - Content: title, description, cta (from base) + secondaryButton
13
+ * - Design: backgroundColor (from base)
14
+ * - Advanced: className, id (from base)
15
+ *
16
+ * Note: The base CTA fields serve as the primary button
17
+ */
18
+
19
+ // CTA-specific content fields (secondary button) - grouped in UI
20
+ const ctaContentFields: FieldDefinition[] = [
21
+ {
22
+ name: 'secondaryButton.text',
23
+ label: 'Text',
24
+ type: 'text',
25
+ tab: 'content',
26
+ required: false,
27
+ placeholder: 'Learn More',
28
+ helpText: 'Button text',
29
+ group: 'secondaryButton',
30
+ groupLabel: 'Secondary Button',
31
+ },
32
+ {
33
+ name: 'secondaryButton.link',
34
+ label: 'Link',
35
+ type: 'url',
36
+ tab: 'content',
37
+ required: false,
38
+ placeholder: '/about or https://...',
39
+ helpText: 'URL the button links to',
40
+ group: 'secondaryButton',
41
+ },
42
+ {
43
+ name: 'secondaryButton.target',
44
+ label: 'Open in',
45
+ type: 'select',
46
+ tab: 'content',
47
+ required: false,
48
+ default: '_self',
49
+ helpText: 'How the link opens',
50
+ group: 'secondaryButton',
51
+ options: [
52
+ { label: 'Same window', value: '_self' },
53
+ { label: 'New tab', value: '_blank' },
54
+ ],
55
+ },
56
+ {
57
+ name: 'secondaryButton.variant',
58
+ label: 'Style',
59
+ type: 'select',
60
+ tab: 'content',
61
+ required: false,
62
+ default: 'outline',
63
+ helpText: 'Visual style of the button',
64
+ group: 'secondaryButton',
65
+ options: [
66
+ { label: 'Default', value: 'default' },
67
+ { label: 'Outline', value: 'outline' },
68
+ { label: 'Ghost', value: 'ghost' },
69
+ ],
70
+ },
71
+ ]
72
+
73
+ /**
74
+ * Complete field definitions organized by tab
75
+ */
76
+ export const fieldDefinitions: FieldDefinition[] = [
77
+ // Content tab: base fields + cta-specific
78
+ ...baseContentFields,
79
+ ...ctaContentFields,
80
+
81
+ // Design tab: base fields only
82
+ ...baseDesignFields,
83
+
84
+ // Advanced tab: base fields only
85
+ ...baseAdvancedFields,
86
+ ]
87
+
88
+ // Alias for compatibility
89
+ export const fields = fieldDefinitions
@@ -0,0 +1,6 @@
1
+ export { config } from './config'
2
+ export { schema } from './schema'
3
+ export { fields } from './fields'
4
+ export { CTASectionBlock as Component } from './component'
5
+
6
+ export type { CTASectionBlockProps } from './schema'
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod'
2
+ import { baseBlockSchema, ctaSchema } from '@nextsparkjs/core/types/blocks'
3
+
4
+ /**
5
+ * Secondary Button Schema (CTA-specific)
6
+ * Uses same structure as CTA but with outline variant default
7
+ */
8
+ const secondaryButtonSchema = ctaSchema.extend({
9
+ variant: z.enum(['default', 'outline', 'ghost']).default('outline'),
10
+ })
11
+
12
+ export type SecondaryButton = z.infer<typeof secondaryButtonSchema>
13
+
14
+ /**
15
+ * CTA Section Block Schema
16
+ *
17
+ * Extends base schema with:
18
+ * - secondaryButton: Optional secondary CTA button
19
+ *
20
+ * Note: Uses base schema title, description, cta (as primary), backgroundColor, className, id
21
+ */
22
+ export const ctaSectionSpecificSchema = z.object({
23
+ // Content: secondary button option
24
+ secondaryButton: secondaryButtonSchema.optional(),
25
+ })
26
+
27
+ /**
28
+ * Complete CTA Section Block Schema
29
+ */
30
+ export const schema = baseBlockSchema.extend(ctaSectionSpecificSchema.shape)
31
+
32
+ export type CTASectionBlockProps = z.infer<typeof schema>
@@ -0,0 +1,119 @@
1
+ import React from 'react'
2
+ // Icon names come from page content, so there is no build-time set to import
3
+ // from the way entity and sidebar icons have (see core's lib/icons). lucide's
4
+ // by-name loader resolves them, but it declares a chunk per icon and that map
5
+ // lands in webpack's runtime, which every route in the app pays for — to spare
6
+ // the few that render this block.
7
+ import * as Icons from 'lucide-react'
8
+ import { cn } from '@nextsparkjs/core/lib/utils'
9
+ import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
10
+ import type { FeaturesGridBlockProps, FeatureItem } from './schema'
11
+
12
+ /**
13
+ * Features Grid Block Component
14
+ *
15
+ * Props from 3-tab structure:
16
+ * - Content: title, content, cta, items
17
+ * - Design: backgroundColor, columns
18
+ * - Advanced: className, id
19
+ */
20
+ export function FeaturesGridBlock({
21
+ // Base content props
22
+ title,
23
+ content,
24
+ cta,
25
+ // Features-specific content
26
+ items,
27
+ // Base design props
28
+ backgroundColor,
29
+ // Features-specific design
30
+ columns = '3',
31
+ // Base advanced props
32
+ className,
33
+ id,
34
+ // Legacy props for backward compatibility
35
+ ...legacyProps
36
+ }: FeaturesGridBlockProps & { features?: FeatureItem[]; description?: string }) {
37
+ // Handle legacy 'features' prop for backward compatibility
38
+ const safeItems = Array.isArray(items)
39
+ ? items
40
+ : Array.isArray((legacyProps as { features?: FeatureItem[] }).features)
41
+ ? (legacyProps as { features: FeatureItem[] }).features
42
+ : []
43
+
44
+ // Handle legacy description prop
45
+ const displayContent = content || (legacyProps as { description?: string }).description
46
+
47
+ // Build column classes based on columns prop
48
+ const columnClasses: Record<string, string> = {
49
+ '2': '@sm:grid-cols-2',
50
+ '3': '@sm:grid-cols-2 @lg:grid-cols-3',
51
+ '4': '@sm:grid-cols-2 @lg:grid-cols-4',
52
+ }
53
+
54
+ // Build section classes with background and custom className
55
+ const sectionClasses = buildSectionClasses(
56
+ 'py-16 px-4 @md:py-24',
57
+ { backgroundColor, className }
58
+ )
59
+
60
+ return (
61
+ <section id={id} className={sectionClasses} data-cy="block-features-grid">
62
+ <div className="container mx-auto max-w-6xl">
63
+ {/* Section Header */}
64
+ {(title || displayContent) && (
65
+ <div className="mb-12 text-center">
66
+ {title && (
67
+ <h2 className="mb-4 text-4xl font-bold @md:text-5xl">
68
+ {title}
69
+ </h2>
70
+ )}
71
+ {displayContent && (
72
+ <p className="mx-auto max-w-2xl text-lg text-muted-foreground">
73
+ {displayContent}
74
+ </p>
75
+ )}
76
+ </div>
77
+ )}
78
+
79
+ {/* Features Grid */}
80
+ <div className={cn('grid gap-8', columnClasses[columns] || columnClasses['3'])}>
81
+ {safeItems.map((item, index) => {
82
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
+ const IconComponent = (Icons as any)[item.icon] || Icons.Circle
84
+
85
+ return (
86
+ <div
87
+ key={index}
88
+ className="flex flex-col items-center text-center p-6 rounded-lg border bg-card"
89
+ >
90
+ <div className="mb-4 rounded-full bg-primary/10 p-4">
91
+ <IconComponent className="h-8 w-8 text-primary" />
92
+ </div>
93
+ <h3 className="mb-2 text-xl font-semibold">{item.title}</h3>
94
+ <p className="text-muted-foreground">{item.description}</p>
95
+ </div>
96
+ )
97
+ })}
98
+ </div>
99
+
100
+ {/* Optional CTA */}
101
+ {cta && (
102
+ <div className="mt-12 text-center">
103
+ <a
104
+ href={cta.link}
105
+ target={cta.target}
106
+ rel={cta.target === '_blank' ? 'noopener noreferrer' : undefined}
107
+ className="inline-flex items-center justify-center rounded-md bg-primary px-8 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
108
+ >
109
+ {cta.text}
110
+ </a>
111
+ </div>
112
+ )}
113
+ </div>
114
+ </section>
115
+ )
116
+ }
117
+
118
+ // The generated block registry imports this as the module's default.
119
+ export default FeaturesGridBlock
@@ -0,0 +1,11 @@
1
+ import type { BlockConfig } from '@nextsparkjs/core/types/blocks'
2
+
3
+ export const config: Omit<BlockConfig, 'schema' | 'fieldDefinitions' | 'Component' | 'examples'> = {
4
+ slug: 'features-grid',
5
+ name: 'Features Grid',
6
+ description: 'Grid layout displaying multiple features with icons, titles, and descriptions',
7
+ category: 'content',
8
+ icon: 'Grid',
9
+ thumbnail: '/theme/blocks/features-grid/thumbnail.png',
10
+ scope: ['pages']
11
+ }
@@ -0,0 +1,97 @@
1
+ import type { FieldDefinition } from '@nextsparkjs/core/types/blocks'
2
+ import {
3
+ baseContentFields,
4
+ baseDesignFields,
5
+ baseAdvancedFields,
6
+ } from '@nextsparkjs/core/types/blocks'
7
+
8
+ /**
9
+ * Features Grid Block Field Definitions
10
+ *
11
+ * Organized into 3 tabs:
12
+ * - Content: title, description, cta (from base) + items array
13
+ * - Design: backgroundColor (from base) + columns
14
+ * - Advanced: className, id (from base)
15
+ */
16
+
17
+ // Features-specific content fields
18
+ const featuresContentFields: FieldDefinition[] = [
19
+ {
20
+ name: 'items',
21
+ label: 'Features',
22
+ type: 'array',
23
+ tab: 'content',
24
+ required: true,
25
+ description: 'List of features to display in the grid',
26
+ helpText: 'Add up to 12 features with icon, title, and description',
27
+ minItems: 1,
28
+ maxItems: 12,
29
+ itemFields: [
30
+ {
31
+ name: 'icon',
32
+ label: 'Icon Name',
33
+ type: 'text',
34
+ tab: 'content',
35
+ required: true,
36
+ placeholder: 'Zap',
37
+ helpText: 'Lucide icon name (e.g., Zap, Shield, Star, Check)',
38
+ },
39
+ {
40
+ name: 'title',
41
+ label: 'Feature Title',
42
+ type: 'text',
43
+ tab: 'content',
44
+ required: true,
45
+ placeholder: 'Lightning Fast',
46
+ maxLength: 100,
47
+ },
48
+ {
49
+ name: 'description',
50
+ label: 'Description',
51
+ type: 'textarea',
52
+ tab: 'content',
53
+ required: true,
54
+ placeholder: 'Describe this feature...',
55
+ maxLength: 300,
56
+ rows: 2,
57
+ },
58
+ ],
59
+ },
60
+ ]
61
+
62
+ // Features-specific design fields
63
+ const featuresDesignFields: FieldDefinition[] = [
64
+ {
65
+ name: 'columns',
66
+ label: 'Grid Columns',
67
+ type: 'select',
68
+ tab: 'design',
69
+ required: false,
70
+ default: '3',
71
+ description: 'Number of columns in the grid layout',
72
+ options: [
73
+ { label: '2 Columns', value: '2' },
74
+ { label: '3 Columns', value: '3' },
75
+ { label: '4 Columns', value: '4' },
76
+ ],
77
+ },
78
+ ]
79
+
80
+ /**
81
+ * Complete field definitions organized by tab
82
+ */
83
+ export const fieldDefinitions: FieldDefinition[] = [
84
+ // Content tab: base fields + features-specific
85
+ ...baseContentFields,
86
+ ...featuresContentFields,
87
+
88
+ // Design tab: base fields + features-specific
89
+ ...baseDesignFields,
90
+ ...featuresDesignFields,
91
+
92
+ // Advanced tab: base fields only
93
+ ...baseAdvancedFields,
94
+ ]
95
+
96
+ // Alias for compatibility
97
+ export const fields = fieldDefinitions
@@ -0,0 +1,6 @@
1
+ export { config } from './config'
2
+ export { schema } from './schema'
3
+ export { fields } from './fields'
4
+ export { FeaturesGridBlock as Component } from './component'
5
+
6
+ export type { FeaturesGridBlockProps } from './schema'
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod'
2
+ import { baseBlockSchema } from '@nextsparkjs/core/types/blocks'
3
+
4
+ /**
5
+ * Feature Item Schema
6
+ * Individual feature in the grid
7
+ */
8
+ const featureItemSchema = z.object({
9
+ icon: z.string().min(1, 'Icon name is required'),
10
+ title: z.string().min(1, 'Feature title is required').max(100),
11
+ description: z.string().min(1, 'Description is required').max(300),
12
+ })
13
+
14
+ export type FeatureItem = z.infer<typeof featureItemSchema>
15
+
16
+ /**
17
+ * Features Grid Block Schema
18
+ *
19
+ * Extends base schema with:
20
+ * - items: Array of feature items (icon, title, description)
21
+ * - columns: Grid layout option (2, 3, 4 columns)
22
+ *
23
+ * Note: Uses base schema title, description, cta, backgroundColor, className, id
24
+ */
25
+ export const featuresGridSpecificSchema = z.object({
26
+ // Content: array of feature items
27
+ items: z.array(featureItemSchema)
28
+ .min(1, 'At least one feature is required')
29
+ .max(12, 'Maximum 12 features allowed'),
30
+
31
+ // Design: column layout
32
+ columns: z.enum(['2', '3', '4']).default('3'),
33
+ })
34
+
35
+ /**
36
+ * Complete Features Grid Block Schema
37
+ */
38
+ export const schema = baseBlockSchema.extend(featuresGridSpecificSchema.shape)
39
+
40
+ export type FeaturesGridBlockProps = z.infer<typeof schema>