@nextsparkjs/theme-default 0.1.0-beta.1

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 (333) hide show
  1. package/about/business.md +49 -0
  2. package/about/features.json +302 -0
  3. package/about/team.md +79 -0
  4. package/api/ai/chat/stream/route.ts +212 -0
  5. package/api/ai/orchestrator/route.ts +226 -0
  6. package/api/ai/single-agent/route.ts +291 -0
  7. package/api/ai/usage/route.ts +122 -0
  8. package/blocks/benefits/component.tsx +100 -0
  9. package/blocks/benefits/config.ts +11 -0
  10. package/blocks/benefits/examples.ts +85 -0
  11. package/blocks/benefits/fields.ts +156 -0
  12. package/blocks/benefits/schema.ts +33 -0
  13. package/blocks/cta-section/component.tsx +100 -0
  14. package/blocks/cta-section/config.ts +11 -0
  15. package/blocks/cta-section/examples.ts +41 -0
  16. package/blocks/cta-section/fields.ts +89 -0
  17. package/blocks/cta-section/index.ts +6 -0
  18. package/blocks/cta-section/schema.ts +32 -0
  19. package/blocks/cta-section/thumbnail.png +1 -0
  20. package/blocks/faq-accordion/component.tsx +156 -0
  21. package/blocks/faq-accordion/config.ts +11 -0
  22. package/blocks/faq-accordion/examples.ts +77 -0
  23. package/blocks/faq-accordion/fields.ts +119 -0
  24. package/blocks/faq-accordion/index.ts +6 -0
  25. package/blocks/faq-accordion/schema.ts +45 -0
  26. package/blocks/features-grid/component.tsx +112 -0
  27. package/blocks/features-grid/config.ts +11 -0
  28. package/blocks/features-grid/examples.ts +63 -0
  29. package/blocks/features-grid/fields.ts +97 -0
  30. package/blocks/features-grid/index.ts +6 -0
  31. package/blocks/features-grid/schema.ts +40 -0
  32. package/blocks/features-grid/thumbnail.png +1 -0
  33. package/blocks/hero/component.tsx +100 -0
  34. package/blocks/hero/config.ts +11 -0
  35. package/blocks/hero/examples.ts +35 -0
  36. package/blocks/hero/fields.ts +60 -0
  37. package/blocks/hero/index.ts +6 -0
  38. package/blocks/hero/schema.ts +32 -0
  39. package/blocks/hero/thumbnail.png +1 -0
  40. package/blocks/hero/thumbnail.png.txt +6 -0
  41. package/blocks/hero-with-form/component.tsx +232 -0
  42. package/blocks/hero-with-form/config.ts +11 -0
  43. package/blocks/hero-with-form/examples.ts +16 -0
  44. package/blocks/hero-with-form/fields.ts +207 -0
  45. package/blocks/hero-with-form/index.ts +6 -0
  46. package/blocks/hero-with-form/schema.ts +54 -0
  47. package/blocks/jumbotron/component.tsx +136 -0
  48. package/blocks/jumbotron/config.ts +11 -0
  49. package/blocks/jumbotron/examples.ts +36 -0
  50. package/blocks/jumbotron/fields.ts +202 -0
  51. package/blocks/jumbotron/index.ts +6 -0
  52. package/blocks/jumbotron/schema.ts +55 -0
  53. package/blocks/logo-cloud/component.tsx +154 -0
  54. package/blocks/logo-cloud/config.ts +11 -0
  55. package/blocks/logo-cloud/examples.ts +34 -0
  56. package/blocks/logo-cloud/fields.ts +133 -0
  57. package/blocks/logo-cloud/index.ts +6 -0
  58. package/blocks/logo-cloud/schema.ts +46 -0
  59. package/blocks/post-content/component.tsx +197 -0
  60. package/blocks/post-content/config.ts +11 -0
  61. package/blocks/post-content/examples.ts +33 -0
  62. package/blocks/post-content/fields.ts +165 -0
  63. package/blocks/post-content/index.ts +4 -0
  64. package/blocks/post-content/schema.ts +46 -0
  65. package/blocks/pricing-table/component.tsx +154 -0
  66. package/blocks/pricing-table/config.ts +11 -0
  67. package/blocks/pricing-table/examples.ts +96 -0
  68. package/blocks/pricing-table/fields.ts +161 -0
  69. package/blocks/pricing-table/index.ts +4 -0
  70. package/blocks/pricing-table/schema.ts +50 -0
  71. package/blocks/split-content/component.tsx +135 -0
  72. package/blocks/split-content/config.ts +11 -0
  73. package/blocks/split-content/examples.ts +38 -0
  74. package/blocks/split-content/fields.ts +198 -0
  75. package/blocks/split-content/index.ts +6 -0
  76. package/blocks/split-content/schema.ts +67 -0
  77. package/blocks/stats-counter/component.tsx +124 -0
  78. package/blocks/stats-counter/config.ts +11 -0
  79. package/blocks/stats-counter/examples.ts +61 -0
  80. package/blocks/stats-counter/fields.ts +134 -0
  81. package/blocks/stats-counter/index.ts +6 -0
  82. package/blocks/stats-counter/schema.ts +47 -0
  83. package/blocks/testimonials/component.tsx +114 -0
  84. package/blocks/testimonials/config.ts +11 -0
  85. package/blocks/testimonials/examples.ts +65 -0
  86. package/blocks/testimonials/fields.ts +105 -0
  87. package/blocks/testimonials/index.ts +6 -0
  88. package/blocks/testimonials/schema.ts +41 -0
  89. package/blocks/testimonials/thumbnail.png +1 -0
  90. package/blocks/text-content/component.tsx +97 -0
  91. package/blocks/text-content/config.ts +11 -0
  92. package/blocks/text-content/examples.ts +30 -0
  93. package/blocks/text-content/fields.ts +88 -0
  94. package/blocks/text-content/index.ts +6 -0
  95. package/blocks/text-content/schema.ts +30 -0
  96. package/blocks/text-content/thumbnail.png +1 -0
  97. package/blocks/timeline/component.tsx +267 -0
  98. package/blocks/timeline/config.ts +11 -0
  99. package/blocks/timeline/examples.ts +68 -0
  100. package/blocks/timeline/fields.ts +147 -0
  101. package/blocks/timeline/index.ts +6 -0
  102. package/blocks/timeline/schema.ts +49 -0
  103. package/blocks/video-hero/component.tsx +270 -0
  104. package/blocks/video-hero/config.ts +11 -0
  105. package/blocks/video-hero/examples.ts +24 -0
  106. package/blocks/video-hero/fields.ts +98 -0
  107. package/blocks/video-hero/index.ts +6 -0
  108. package/blocks/video-hero/schema.ts +39 -0
  109. package/components/ai-chat/ChatPanel.tsx +575 -0
  110. package/components/ai-chat/ConversationItem.tsx +266 -0
  111. package/components/ai-chat/ConversationSidebar.tsx +99 -0
  112. package/components/ai-chat/MarkdownRenderer.tsx +15 -0
  113. package/components/ai-chat/Message.tsx +42 -0
  114. package/components/ai-chat/MessageInput.tsx +49 -0
  115. package/components/ai-chat/MessageList.tsx +46 -0
  116. package/components/ai-chat/TypingIndicator.tsx +11 -0
  117. package/config/app.config.ts +367 -0
  118. package/config/billing.config.ts +349 -0
  119. package/config/dashboard.config.ts +506 -0
  120. package/config/dev.config.ts +104 -0
  121. package/config/features.config.ts +203 -0
  122. package/config/flows.config.ts +129 -0
  123. package/config/permissions.config.ts +245 -0
  124. package/config/theme.config.ts +74 -0
  125. package/docs/01-overview/01-introduction.md +335 -0
  126. package/docs/01-overview/02-customization.md +671 -0
  127. package/docs/02-features/01-components.md +155 -0
  128. package/docs/02-features/02-styling.md +139 -0
  129. package/docs/02-features/03-tasks-entity.md +407 -0
  130. package/docs/03-ai/01-overview.md +211 -0
  131. package/docs/03-ai/02-customization.md +436 -0
  132. package/entities/customers/customers.config.ts +75 -0
  133. package/entities/customers/customers.fields.ts +165 -0
  134. package/entities/customers/customers.service.ts +516 -0
  135. package/entities/customers/customers.types.ts +83 -0
  136. package/entities/customers/messages/en.json +66 -0
  137. package/entities/customers/messages/es.json +66 -0
  138. package/entities/customers/migrations/001_customers_table.sql +102 -0
  139. package/entities/customers/migrations/002_customers_metas.sql +92 -0
  140. package/entities/pages/messages/en.json +41 -0
  141. package/entities/pages/messages/es.json +41 -0
  142. package/entities/pages/migrations/001_pages_table.sql +112 -0
  143. package/entities/pages/migrations/002_pages_metas.sql +56 -0
  144. package/entities/pages/migrations/003_add_status.sql +50 -0
  145. package/entities/pages/pages-management.service.ts +610 -0
  146. package/entities/pages/pages.config.ts +94 -0
  147. package/entities/pages/pages.fields.ts +101 -0
  148. package/entities/pages/pages.service.ts +290 -0
  149. package/entities/pages/pages.types.ts +124 -0
  150. package/entities/posts/components/post-header.tsx +97 -0
  151. package/entities/posts/messages/en.json +55 -0
  152. package/entities/posts/messages/es.json +55 -0
  153. package/entities/posts/migrations/001_posts_table.sql +115 -0
  154. package/entities/posts/migrations/003_add_status.sql +44 -0
  155. package/entities/posts/migrations/004_entity_taxonomy_relations.sql +129 -0
  156. package/entities/posts/migrations/006_posts_metas.sql +56 -0
  157. package/entities/posts/posts.config.ts +101 -0
  158. package/entities/posts/posts.fields.ts +116 -0
  159. package/entities/posts/posts.service.ts +376 -0
  160. package/entities/posts/posts.types.ts +74 -0
  161. package/entities/tasks/messages/en.json +204 -0
  162. package/entities/tasks/messages/es.json +204 -0
  163. package/entities/tasks/migrations/001_tasks_table.sql +105 -0
  164. package/entities/tasks/migrations/002_task_metas.sql +85 -0
  165. package/entities/tasks/migrations/sample_data.json +77 -0
  166. package/entities/tasks/tasks.config.ts +79 -0
  167. package/entities/tasks/tasks.fields.ts +196 -0
  168. package/entities/tasks/tasks.service.ts +541 -0
  169. package/entities/tasks/tasks.types.ts +56 -0
  170. package/lib/hooks/useAiChat.ts +114 -0
  171. package/lib/hooks/useConversations.ts +376 -0
  172. package/lib/hooks/useOrchestratorChat.ts +122 -0
  173. package/lib/hooks/usePersistentChat.ts +315 -0
  174. package/lib/hooks/useStreamingChat.ts +127 -0
  175. package/lib/hooks/useTokenUsage.ts +63 -0
  176. package/lib/langchain/agents/customer-assistant.md +69 -0
  177. package/lib/langchain/agents/index.ts +61 -0
  178. package/lib/langchain/agents/orchestrator.md +59 -0
  179. package/lib/langchain/agents/page-assistant.md +85 -0
  180. package/lib/langchain/agents/single-agent.md +46 -0
  181. package/lib/langchain/agents/task-assistant.md +55 -0
  182. package/lib/langchain/config.ts +45 -0
  183. package/lib/langchain/handlers/customer-handler.ts +338 -0
  184. package/lib/langchain/handlers/page-handler.ts +232 -0
  185. package/lib/langchain/handlers/task-handler.ts +323 -0
  186. package/lib/langchain/langchain.config.ts +223 -0
  187. package/lib/langchain/observability.config.ts +30 -0
  188. package/lib/langchain/orchestrator.ts +562 -0
  189. package/lib/langchain/tools/customers.ts +176 -0
  190. package/lib/langchain/tools/index.ts +10 -0
  191. package/lib/langchain/tools/orchestrator.ts +92 -0
  192. package/lib/langchain/tools/pages.ts +289 -0
  193. package/lib/langchain/tools/tasks.ts +167 -0
  194. package/lib/scheduled-actions/billing.ts +149 -0
  195. package/lib/scheduled-actions/index.ts +170 -0
  196. package/lib/scheduled-actions/webhook.ts +231 -0
  197. package/lib/selectors.ts +197 -0
  198. package/messages/de/admin.json +219 -0
  199. package/messages/de/aiUsage.json +36 -0
  200. package/messages/de/buttons.json +19 -0
  201. package/messages/de/categories.json +35 -0
  202. package/messages/de/common.json +16 -0
  203. package/messages/de/dev.json +101 -0
  204. package/messages/de/docs.json +27 -0
  205. package/messages/de/entities.json +7 -0
  206. package/messages/de/features.json +119 -0
  207. package/messages/de/footer.json +22 -0
  208. package/messages/de/home.json +57 -0
  209. package/messages/de/index.ts +39 -0
  210. package/messages/de/mobileNav.json +13 -0
  211. package/messages/de/navigation.json +8 -0
  212. package/messages/de/observability.json +74 -0
  213. package/messages/de/posts.json +54 -0
  214. package/messages/de/pricing.json +102 -0
  215. package/messages/de/support.json +9 -0
  216. package/messages/de/teams.json +8 -0
  217. package/messages/en/admin.json +219 -0
  218. package/messages/en/aiUsage.json +36 -0
  219. package/messages/en/buttons.json +19 -0
  220. package/messages/en/categories.json +35 -0
  221. package/messages/en/common.json +16 -0
  222. package/messages/en/dev.json +106 -0
  223. package/messages/en/docs.json +27 -0
  224. package/messages/en/entities.json +7 -0
  225. package/messages/en/features.json +119 -0
  226. package/messages/en/footer.json +22 -0
  227. package/messages/en/home.json +57 -0
  228. package/messages/en/index.ts +39 -0
  229. package/messages/en/mobileNav.json +13 -0
  230. package/messages/en/navigation.json +8 -0
  231. package/messages/en/observability.json +74 -0
  232. package/messages/en/posts.json +54 -0
  233. package/messages/en/pricing.json +102 -0
  234. package/messages/en/support.json +9 -0
  235. package/messages/en/teams.json +8 -0
  236. package/messages/es/admin.json +219 -0
  237. package/messages/es/aiUsage.json +36 -0
  238. package/messages/es/buttons.json +19 -0
  239. package/messages/es/categories.json +35 -0
  240. package/messages/es/common.json +16 -0
  241. package/messages/es/dev.json +101 -0
  242. package/messages/es/docs.json +27 -0
  243. package/messages/es/entities.json +7 -0
  244. package/messages/es/features.json +119 -0
  245. package/messages/es/footer.json +22 -0
  246. package/messages/es/home.json +57 -0
  247. package/messages/es/index.ts +39 -0
  248. package/messages/es/mobileNav.json +13 -0
  249. package/messages/es/navigation.json +8 -0
  250. package/messages/es/observability.json +74 -0
  251. package/messages/es/posts.json +54 -0
  252. package/messages/es/pricing.json +102 -0
  253. package/messages/es/support.json +9 -0
  254. package/messages/es/teams.json +8 -0
  255. package/messages/fr/admin.json +219 -0
  256. package/messages/fr/aiUsage.json +36 -0
  257. package/messages/fr/buttons.json +19 -0
  258. package/messages/fr/categories.json +35 -0
  259. package/messages/fr/common.json +16 -0
  260. package/messages/fr/dev.json +101 -0
  261. package/messages/fr/docs.json +27 -0
  262. package/messages/fr/entities.json +7 -0
  263. package/messages/fr/features.json +119 -0
  264. package/messages/fr/footer.json +22 -0
  265. package/messages/fr/home.json +57 -0
  266. package/messages/fr/index.ts +39 -0
  267. package/messages/fr/mobileNav.json +13 -0
  268. package/messages/fr/navigation.json +8 -0
  269. package/messages/fr/observability.json +74 -0
  270. package/messages/fr/posts.json +54 -0
  271. package/messages/fr/pricing.json +102 -0
  272. package/messages/fr/support.json +9 -0
  273. package/messages/fr/teams.json +8 -0
  274. package/messages/it/admin.json +219 -0
  275. package/messages/it/aiUsage.json +36 -0
  276. package/messages/it/buttons.json +19 -0
  277. package/messages/it/categories.json +35 -0
  278. package/messages/it/common.json +16 -0
  279. package/messages/it/dev.json +101 -0
  280. package/messages/it/docs.json +27 -0
  281. package/messages/it/entities.json +7 -0
  282. package/messages/it/features.json +119 -0
  283. package/messages/it/footer.json +22 -0
  284. package/messages/it/home.json +57 -0
  285. package/messages/it/index.ts +39 -0
  286. package/messages/it/mobileNav.json +13 -0
  287. package/messages/it/navigation.json +8 -0
  288. package/messages/it/observability.json +74 -0
  289. package/messages/it/posts.json +54 -0
  290. package/messages/it/pricing.json +102 -0
  291. package/messages/it/support.json +9 -0
  292. package/messages/it/teams.json +8 -0
  293. package/messages/pt/admin.json +219 -0
  294. package/messages/pt/aiUsage.json +36 -0
  295. package/messages/pt/buttons.json +19 -0
  296. package/messages/pt/categories.json +35 -0
  297. package/messages/pt/common.json +16 -0
  298. package/messages/pt/dev.json +101 -0
  299. package/messages/pt/docs.json +27 -0
  300. package/messages/pt/entities.json +7 -0
  301. package/messages/pt/features.json +119 -0
  302. package/messages/pt/footer.json +22 -0
  303. package/messages/pt/home.json +57 -0
  304. package/messages/pt/index.ts +39 -0
  305. package/messages/pt/mobileNav.json +13 -0
  306. package/messages/pt/navigation.json +8 -0
  307. package/messages/pt/observability.json +74 -0
  308. package/messages/pt/posts.json +54 -0
  309. package/messages/pt/pricing.json +102 -0
  310. package/messages/pt/support.json +9 -0
  311. package/messages/pt/teams.json +8 -0
  312. package/migrations/089_add_editor_team_role.sql +39 -0
  313. package/migrations/090_demo_users_teams.sql +540 -0
  314. package/migrations/091_greek_teams_billing.sql +523 -0
  315. package/migrations/092_billing_sample_data.sql +774 -0
  316. package/migrations/093_pages_sample_data.sql +1158 -0
  317. package/migrations/094_posts_sample_data.sql +278 -0
  318. package/migrations/095_tasks_sample_data.sql +440 -0
  319. package/migrations/096_customers_sample_data.sql +358 -0
  320. package/migrations/097_scheduled_actions_sample_data.sql +111 -0
  321. package/package.json +22 -0
  322. package/public/docs/desktop-layout-example.png +0 -0
  323. package/styles/components.css +11 -0
  324. package/styles/globals.css +179 -0
  325. package/templates/(public)/blog/[slug]/page.tsx +65 -0
  326. package/templates/(public)/layout.tsx +25 -0
  327. package/templates/(public)/page.tsx +200 -0
  328. package/templates/(public)/support/page.tsx +321 -0
  329. package/templates/dashboard/(main)/agent-multi/page.tsx +63 -0
  330. package/templates/dashboard/(main)/agent-single/page.tsx +142 -0
  331. package/templates/dashboard/(main)/settings/ai-usage/page.tsx +157 -0
  332. package/templates/superadmin/ai-observability/[traceId]/page.tsx +27 -0
  333. package/templates/superadmin/ai-observability/page.tsx +17 -0
@@ -0,0 +1,97 @@
1
+ import React from 'react'
2
+ import { cn } from '@nextsparkjs/core/lib/utils'
3
+ import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
4
+ import { sel } from '../../lib/selectors'
5
+ import type { TextContentBlockProps } from './schema'
6
+
7
+ /**
8
+ * Text Content Block Component
9
+ *
10
+ * Props from 3-tab structure:
11
+ * - Content: title, content (rich-text), cta
12
+ * - Design: backgroundColor, maxWidth, alignment
13
+ * - Advanced: className, id
14
+ *
15
+ * Note: `content` is the main rich-text body of this block
16
+ */
17
+ export function TextContentBlock({
18
+ // Base content props
19
+ title,
20
+ content,
21
+ cta,
22
+ // Base design props
23
+ backgroundColor,
24
+ // Text-content-specific design
25
+ maxWidth = 'lg',
26
+ alignment = 'left',
27
+ // Base advanced props
28
+ className,
29
+ id,
30
+ }: TextContentBlockProps) {
31
+ const maxWidthClasses: Record<string, string> = {
32
+ sm: 'max-w-2xl',
33
+ md: 'max-w-3xl',
34
+ lg: 'max-w-4xl',
35
+ xl: 'max-w-5xl',
36
+ full: 'max-w-none',
37
+ }
38
+
39
+ const alignmentClasses: Record<string, string> = {
40
+ left: 'text-left',
41
+ center: 'text-center mx-auto',
42
+ right: 'text-right ml-auto',
43
+ }
44
+
45
+ // Build section classes with background and custom className
46
+ const sectionClasses = buildSectionClasses(
47
+ 'py-16 px-4 md:py-24',
48
+ { backgroundColor, className }
49
+ )
50
+
51
+ return (
52
+ <section id={id} className={sectionClasses} data-cy={sel('blocks.textContent.container')}>
53
+ <div className="container mx-auto">
54
+ {/* Optional Section Title */}
55
+ {title && (
56
+ <div className={cn(
57
+ 'mb-8',
58
+ maxWidthClasses[maxWidth],
59
+ alignmentClasses[alignment]
60
+ )}>
61
+ <h2 className="text-3xl font-bold md:text-4xl">
62
+ {title}
63
+ </h2>
64
+ </div>
65
+ )}
66
+
67
+ {/* Rich Text Content */}
68
+ <div
69
+ className={cn(
70
+ 'prose prose-lg dark:prose-invert',
71
+ maxWidthClasses[maxWidth],
72
+ alignmentClasses[alignment]
73
+ )}
74
+ dangerouslySetInnerHTML={{ __html: content }}
75
+ />
76
+
77
+ {/* Optional CTA */}
78
+ {cta && (
79
+ <div className={cn(
80
+ 'mt-8',
81
+ maxWidthClasses[maxWidth],
82
+ alignmentClasses[alignment]
83
+ )}>
84
+ <a
85
+ href={cta.link}
86
+ target={cta.target}
87
+ rel={cta.target === '_blank' ? 'noopener noreferrer' : undefined}
88
+ 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"
89
+ >
90
+ {cta.text}
91
+ </a>
92
+ </div>
93
+ )}
94
+ </div>
95
+ </section>
96
+ )
97
+ }
@@ -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: 'text-content',
5
+ name: 'Text Content',
6
+ description: 'Rich text content block for paragraphs, lists, and formatted text',
7
+ category: 'content',
8
+ icon: 'FileText',
9
+ thumbnail: '/theme/blocks/text-content/thumbnail.png',
10
+ scope: ['pages']
11
+ }
@@ -0,0 +1,30 @@
1
+ import type { BlockExample } from '@nextsparkjs/core/types/blocks'
2
+
3
+ export const examples: BlockExample[] = [
4
+ {
5
+ name: 'Default',
6
+ description: 'Standard text content block',
7
+ props: {
8
+ title: 'About Our Platform',
9
+ content: `
10
+ <p>We built this platform with one goal in mind: to make professional-grade tools accessible to teams of all sizes. Whether you're a startup or an enterprise, you deserve software that works as hard as you do.</p>
11
+
12
+ <p>Our journey started in 2020 when we recognized a gap in the market for intuitive, powerful collaboration tools. Today, we serve thousands of teams across 150+ countries, helping them streamline their workflows and achieve more.</p>
13
+
14
+ <h3>Our Mission</h3>
15
+ <p>To empower teams with technology that amplifies their capabilities without adding complexity. We believe the best tools are the ones you don't have to think about - they just work.</p>
16
+
17
+ <h3>Core Values</h3>
18
+ <ul>
19
+ <li><strong>Simplicity:</strong> Complex problems deserve simple solutions</li>
20
+ <li><strong>Reliability:</strong> Your work depends on us, we take that seriously</li>
21
+ <li><strong>Innovation:</strong> Constantly evolving to meet your needs</li>
22
+ <li><strong>Support:</strong> Real people, real help, real time</li>
23
+ </ul>
24
+ `,
25
+ backgroundColor: 'white',
26
+ maxWidth: '4xl',
27
+ textAlign: 'left',
28
+ },
29
+ },
30
+ ]
@@ -0,0 +1,88 @@
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
+ * Text Content Block Field Definitions
10
+ *
11
+ * Organized into 3 tabs:
12
+ * - Content: title, cta (from base) + content (rich-text, replaces base content)
13
+ * - Design: backgroundColor (from base) + maxWidth, alignment
14
+ * - Advanced: className, id (from base)
15
+ *
16
+ * Note: The `content` field is overridden with a rich-text version
17
+ */
18
+
19
+ // Filter out base content field (we'll replace it with rich-text version)
20
+ const baseContentFieldsWithoutContent = baseContentFields.filter(
21
+ (field) => field.name !== 'content'
22
+ )
23
+
24
+ // Text-content-specific content fields (rich-text content)
25
+ const textContentFields: FieldDefinition[] = [
26
+ {
27
+ name: 'content',
28
+ label: 'Content',
29
+ type: 'rich-text',
30
+ tab: 'content',
31
+ required: true,
32
+ placeholder: 'Enter your content here...',
33
+ helpText: 'Rich text content with formatting support',
34
+ },
35
+ ]
36
+
37
+ // Text-content-specific design fields
38
+ const textDesignFields: FieldDefinition[] = [
39
+ {
40
+ name: 'maxWidth',
41
+ label: 'Maximum Width',
42
+ type: 'select',
43
+ tab: 'design',
44
+ required: false,
45
+ default: 'lg',
46
+ helpText: 'Maximum content width',
47
+ options: [
48
+ { label: 'Small (640px)', value: 'sm' },
49
+ { label: 'Medium (768px)', value: 'md' },
50
+ { label: 'Large (1024px)', value: 'lg' },
51
+ { label: 'Extra Large (1280px)', value: 'xl' },
52
+ { label: 'Full Width', value: 'full' },
53
+ ],
54
+ },
55
+ {
56
+ name: 'alignment',
57
+ label: 'Text Alignment',
58
+ type: 'select',
59
+ tab: 'design',
60
+ required: false,
61
+ default: 'left',
62
+ helpText: 'Text alignment within the content area',
63
+ options: [
64
+ { label: 'Left', value: 'left' },
65
+ { label: 'Center', value: 'center' },
66
+ { label: 'Right', value: 'right' },
67
+ ],
68
+ },
69
+ ]
70
+
71
+ /**
72
+ * Complete field definitions organized by tab
73
+ */
74
+ export const fieldDefinitions: FieldDefinition[] = [
75
+ // Content tab: base fields (without content) + rich-text content
76
+ ...baseContentFieldsWithoutContent,
77
+ ...textContentFields,
78
+
79
+ // Design tab: base fields + text-specific
80
+ ...baseDesignFields,
81
+ ...textDesignFields,
82
+
83
+ // Advanced tab: base fields only
84
+ ...baseAdvancedFields,
85
+ ]
86
+
87
+ // Alias for compatibility
88
+ 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 { TextContentBlock as Component } from './component'
5
+
6
+ export type { TextContentBlockProps } from './schema'
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod'
2
+ import { baseBlockSchema } from '@nextsparkjs/core/types/blocks'
3
+
4
+ /**
5
+ * Text Content Block Schema
6
+ *
7
+ * Extends base schema with:
8
+ * - content: Rich text/HTML content (overrides base content with required)
9
+ * - maxWidth: Content width constraint
10
+ * - alignment: Text alignment
11
+ *
12
+ * Note: Uses base schema title, cta, backgroundColor, className, id
13
+ * The `content` field is overridden to be required and serves as rich-text body
14
+ */
15
+ export const textContentSpecificSchema = z.object({
16
+ // Content: rich text body (overrides base optional content)
17
+ content: z.string().min(1, 'Content is required'),
18
+
19
+ // Design: layout options
20
+ maxWidth: z.enum(['sm', 'md', 'lg', 'xl', 'full']).default('lg'),
21
+ alignment: z.enum(['left', 'center', 'right']).default('left'),
22
+ })
23
+
24
+ /**
25
+ * Complete Text Content Block Schema
26
+ * Note: textContentSpecificSchema.content overrides baseBlockSchema.content
27
+ */
28
+ export const schema = baseBlockSchema.merge(textContentSpecificSchema)
29
+
30
+ export type TextContentBlockProps = z.infer<typeof schema>
@@ -0,0 +1 @@
1
+ Placeholder
@@ -0,0 +1,267 @@
1
+ import React from 'react'
2
+ import * as Icons from 'lucide-react'
3
+ import { cn } from '@nextsparkjs/core/lib/utils'
4
+ import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
5
+ import { sel } from '../../lib/selectors'
6
+ import type { TimelineBlockProps, TimelineItem } from './schema'
7
+
8
+ /**
9
+ * Timeline Block Component
10
+ *
11
+ * Props from 3-tab structure:
12
+ * - Content: title, subtitle, items
13
+ * - Design: backgroundColor, layout, alternating, showConnector, variant
14
+ * - Advanced: className, id
15
+ */
16
+ export function TimelineBlock({
17
+ // Base content props
18
+ title,
19
+ // Timeline-specific content
20
+ subtitle,
21
+ items,
22
+ // Base design props
23
+ backgroundColor,
24
+ // Timeline-specific design
25
+ layout = 'vertical',
26
+ alternating = true,
27
+ showConnector = true,
28
+ variant = 'default',
29
+ // Base advanced props
30
+ className,
31
+ id,
32
+ }: TimelineBlockProps) {
33
+ // Build section classes with background and custom className
34
+ const sectionClasses = buildSectionClasses(
35
+ 'py-16 px-4 md:py-24',
36
+ { backgroundColor, className }
37
+ )
38
+
39
+ // Safe items array
40
+ const safeItems = Array.isArray(items) ? items : []
41
+
42
+ return (
43
+ <section id={id} className={sectionClasses} data-cy={sel('blocks.timeline.container')}>
44
+ <div className="container mx-auto max-w-6xl">
45
+ {/* Section Header */}
46
+ {(title || subtitle) && (
47
+ <div className="mb-16 text-center">
48
+ {title && (
49
+ <h2 className="mb-4 text-4xl font-bold md:text-5xl">
50
+ {title}
51
+ </h2>
52
+ )}
53
+ {subtitle && (
54
+ <p className="mx-auto max-w-2xl text-lg text-muted-foreground">
55
+ {subtitle}
56
+ </p>
57
+ )}
58
+ </div>
59
+ )}
60
+
61
+ {/* Timeline */}
62
+ {layout === 'vertical' ? (
63
+ <VerticalTimeline
64
+ items={safeItems}
65
+ alternating={alternating}
66
+ showConnector={showConnector}
67
+ variant={variant}
68
+ />
69
+ ) : (
70
+ <HorizontalTimeline
71
+ items={safeItems}
72
+ showConnector={showConnector}
73
+ variant={variant}
74
+ />
75
+ )}
76
+ </div>
77
+ </section>
78
+ )
79
+ }
80
+
81
+ /**
82
+ * Vertical Timeline Layout
83
+ */
84
+ function VerticalTimeline({
85
+ items,
86
+ alternating,
87
+ showConnector,
88
+ variant,
89
+ }: {
90
+ items: TimelineItem[]
91
+ alternating: boolean
92
+ showConnector: boolean
93
+ variant: 'default' | 'minimal' | 'cards'
94
+ }) {
95
+ return (
96
+ <div className="relative">
97
+ {/* Connector Line */}
98
+ {showConnector && (
99
+ <div className="absolute left-1/2 top-0 bottom-0 w-0.5 bg-border -translate-x-1/2 hidden md:block" />
100
+ )}
101
+ {showConnector && (
102
+ <div className="absolute left-8 top-0 bottom-0 w-0.5 bg-border md:hidden" />
103
+ )}
104
+
105
+ {/* Timeline Items */}
106
+ <div className="space-y-12">
107
+ {items.map((item, index) => {
108
+ const isLeft = alternating && index % 2 === 0
109
+
110
+ return (
111
+ <div
112
+ key={index}
113
+ className={cn(
114
+ 'relative flex items-center gap-8',
115
+ alternating ? 'md:justify-center' : 'md:justify-start md:pl-[50%]',
116
+ 'justify-start pl-16 md:pl-0'
117
+ )}
118
+ >
119
+ {/* Mobile/Left Content */}
120
+ <div className={cn(
121
+ 'flex-1',
122
+ alternating && !isLeft && 'md:text-right md:order-1',
123
+ !alternating && 'md:pl-8'
124
+ )}>
125
+ <TimelineItemContent item={item} variant={variant} align={alternating && !isLeft ? 'right' : 'left'} />
126
+ </div>
127
+
128
+ {/* Center Dot */}
129
+ <div className="absolute left-8 md:left-1/2 md:-translate-x-1/2 flex-shrink-0">
130
+ <TimelineIcon item={item} />
131
+ </div>
132
+
133
+ {/* Desktop Spacer (for alternating layout) */}
134
+ {alternating && (
135
+ <div className="hidden md:block flex-1" />
136
+ )}
137
+ </div>
138
+ )
139
+ })}
140
+ </div>
141
+ </div>
142
+ )
143
+ }
144
+
145
+ /**
146
+ * Horizontal Timeline Layout
147
+ * Note: Becomes vertical on mobile for better UX
148
+ */
149
+ function HorizontalTimeline({
150
+ items,
151
+ showConnector,
152
+ variant,
153
+ }: {
154
+ items: TimelineItem[]
155
+ showConnector: boolean
156
+ variant: 'default' | 'minimal' | 'cards'
157
+ }) {
158
+ return (
159
+ <div className="relative">
160
+ {/* Mobile: Vertical Layout */}
161
+ <div className="md:hidden">
162
+ {showConnector && (
163
+ <div className="absolute left-8 top-0 bottom-0 w-0.5 bg-border" />
164
+ )}
165
+ <div className="space-y-12">
166
+ {items.map((item, index) => (
167
+ <div key={index} className="relative pl-16">
168
+ <div className="absolute left-8 -translate-x-1/2">
169
+ <TimelineIcon item={item} />
170
+ </div>
171
+ <TimelineItemContent item={item} variant={variant} align="left" />
172
+ </div>
173
+ ))}
174
+ </div>
175
+ </div>
176
+
177
+ {/* Desktop: Horizontal Layout */}
178
+ <div className="hidden md:block overflow-x-auto pb-4">
179
+ <div className="relative min-w-max">
180
+ {/* Connector Line */}
181
+ {showConnector && (
182
+ <div className="absolute left-0 right-0 top-12 h-0.5 bg-border" />
183
+ )}
184
+
185
+ {/* Timeline Items */}
186
+ <div className="flex gap-8 pt-8">
187
+ {items.map((item, index) => (
188
+ <div key={index} className="relative flex flex-col items-center w-64 flex-shrink-0">
189
+ {/* Icon */}
190
+ <div className="relative z-10 mb-8">
191
+ <TimelineIcon item={item} />
192
+ </div>
193
+
194
+ {/* Content */}
195
+ <TimelineItemContent item={item} variant={variant} align="center" />
196
+ </div>
197
+ ))}
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </div>
202
+ )
203
+ }
204
+
205
+ /**
206
+ * Timeline Icon Component
207
+ */
208
+ function TimelineIcon({ item }: { item: TimelineItem }) {
209
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
210
+ const IconComponent = item.icon ? ((Icons as any)[item.icon] || Icons.Circle) : Icons.Circle
211
+
212
+ return (
213
+ <div className="flex items-center justify-center w-12 h-12 rounded-full bg-primary text-primary-foreground border-4 border-background">
214
+ <IconComponent className="h-5 w-5" />
215
+ </div>
216
+ )
217
+ }
218
+
219
+ /**
220
+ * Timeline Item Content
221
+ */
222
+ function TimelineItemContent({
223
+ item,
224
+ variant,
225
+ align,
226
+ }: {
227
+ item: TimelineItem
228
+ variant: 'default' | 'minimal' | 'cards'
229
+ align: 'left' | 'right' | 'center'
230
+ }) {
231
+ const alignClasses = {
232
+ left: 'text-left',
233
+ right: 'text-right',
234
+ center: 'text-center',
235
+ }
236
+
237
+ const contentClasses = cn(
238
+ alignClasses[align],
239
+ variant === 'cards' && 'p-6 rounded-lg border bg-card shadow-sm',
240
+ variant === 'default' && 'p-4 rounded-lg bg-muted/30',
241
+ variant === 'minimal' && 'p-2'
242
+ )
243
+
244
+ return (
245
+ <div className={contentClasses}>
246
+ {/* Date Badge */}
247
+ <div className={cn(
248
+ 'inline-block mb-2 px-3 py-1 rounded-full text-xs font-semibold bg-primary/10 text-primary',
249
+ align === 'center' && 'mx-auto'
250
+ )}>
251
+ {item.date}
252
+ </div>
253
+
254
+ {/* Title */}
255
+ <h3 className="text-xl font-semibold mb-2">
256
+ {item.title}
257
+ </h3>
258
+
259
+ {/* Description */}
260
+ {item.description && (
261
+ <p className="text-muted-foreground">
262
+ {item.description}
263
+ </p>
264
+ )}
265
+ </div>
266
+ )
267
+ }
@@ -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: 'timeline',
5
+ name: 'Timeline',
6
+ description: 'A vertical or horizontal timeline showing chronological events, process steps, or history',
7
+ category: 'content',
8
+ icon: 'GitBranch',
9
+ thumbnail: '/theme/blocks/timeline/thumbnail.png',
10
+ scope: ['pages', 'posts']
11
+ }
@@ -0,0 +1,68 @@
1
+ import type { BlockExample } from '@nextsparkjs/core/types/blocks'
2
+
3
+ export const examples: BlockExample[] = [
4
+ {
5
+ name: 'Vertical',
6
+ description: 'Vertical timeline layout',
7
+ props: {
8
+ title: 'Our Journey',
9
+ content: 'Key milestones in our growth story',
10
+ backgroundColor: 'white',
11
+ orientation: 'vertical',
12
+ events: [
13
+ {
14
+ date: '2020',
15
+ title: 'Company Founded',
16
+ description: 'Started with a vision to transform how teams collaborate',
17
+ },
18
+ {
19
+ date: '2021',
20
+ title: 'First 1,000 Users',
21
+ description: 'Reached our first major milestone and expanded our team',
22
+ },
23
+ {
24
+ date: '2022',
25
+ title: 'Series A Funding',
26
+ description: 'Secured $10M to accelerate product development',
27
+ },
28
+ {
29
+ date: '2023',
30
+ title: 'Global Expansion',
31
+ description: 'Opened offices in 5 countries and reached 10,000+ customers',
32
+ },
33
+ {
34
+ date: '2024',
35
+ title: 'Platform Launch',
36
+ description: 'Launched next-generation platform with AI-powered features',
37
+ },
38
+ ],
39
+ },
40
+ },
41
+ {
42
+ name: 'Horizontal',
43
+ description: 'Horizontal timeline layout',
44
+ props: {
45
+ title: 'Product Roadmap',
46
+ content: 'What we are building next',
47
+ backgroundColor: 'gray-50',
48
+ orientation: 'horizontal',
49
+ events: [
50
+ {
51
+ date: 'Q1 2024',
52
+ title: 'Advanced Analytics',
53
+ description: 'New dashboard with predictive insights',
54
+ },
55
+ {
56
+ date: 'Q2 2024',
57
+ title: 'Mobile Apps',
58
+ description: 'Native iOS and Android applications',
59
+ },
60
+ {
61
+ date: 'Q3 2024',
62
+ title: 'API v2',
63
+ description: 'Enhanced API with GraphQL support',
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ ]