@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.
- package/about/business.md +49 -0
- package/about/features.json +302 -0
- package/about/team.md +79 -0
- package/api/ai/chat/stream/route.ts +212 -0
- package/api/ai/orchestrator/route.ts +226 -0
- package/api/ai/single-agent/route.ts +291 -0
- package/api/ai/usage/route.ts +122 -0
- package/blocks/benefits/component.tsx +100 -0
- package/blocks/benefits/config.ts +11 -0
- package/blocks/benefits/examples.ts +85 -0
- package/blocks/benefits/fields.ts +156 -0
- package/blocks/benefits/schema.ts +33 -0
- package/blocks/cta-section/component.tsx +100 -0
- package/blocks/cta-section/config.ts +11 -0
- package/blocks/cta-section/examples.ts +41 -0
- package/blocks/cta-section/fields.ts +89 -0
- package/blocks/cta-section/index.ts +6 -0
- package/blocks/cta-section/schema.ts +32 -0
- package/blocks/cta-section/thumbnail.png +1 -0
- package/blocks/faq-accordion/component.tsx +156 -0
- package/blocks/faq-accordion/config.ts +11 -0
- package/blocks/faq-accordion/examples.ts +77 -0
- package/blocks/faq-accordion/fields.ts +119 -0
- package/blocks/faq-accordion/index.ts +6 -0
- package/blocks/faq-accordion/schema.ts +45 -0
- package/blocks/features-grid/component.tsx +112 -0
- package/blocks/features-grid/config.ts +11 -0
- package/blocks/features-grid/examples.ts +63 -0
- package/blocks/features-grid/fields.ts +97 -0
- package/blocks/features-grid/index.ts +6 -0
- package/blocks/features-grid/schema.ts +40 -0
- package/blocks/features-grid/thumbnail.png +1 -0
- package/blocks/hero/component.tsx +100 -0
- package/blocks/hero/config.ts +11 -0
- package/blocks/hero/examples.ts +35 -0
- package/blocks/hero/fields.ts +60 -0
- package/blocks/hero/index.ts +6 -0
- package/blocks/hero/schema.ts +32 -0
- package/blocks/hero/thumbnail.png +1 -0
- package/blocks/hero/thumbnail.png.txt +6 -0
- package/blocks/hero-with-form/component.tsx +232 -0
- package/blocks/hero-with-form/config.ts +11 -0
- package/blocks/hero-with-form/examples.ts +16 -0
- package/blocks/hero-with-form/fields.ts +207 -0
- package/blocks/hero-with-form/index.ts +6 -0
- package/blocks/hero-with-form/schema.ts +54 -0
- package/blocks/jumbotron/component.tsx +136 -0
- package/blocks/jumbotron/config.ts +11 -0
- package/blocks/jumbotron/examples.ts +36 -0
- package/blocks/jumbotron/fields.ts +202 -0
- package/blocks/jumbotron/index.ts +6 -0
- package/blocks/jumbotron/schema.ts +55 -0
- package/blocks/logo-cloud/component.tsx +154 -0
- package/blocks/logo-cloud/config.ts +11 -0
- package/blocks/logo-cloud/examples.ts +34 -0
- package/blocks/logo-cloud/fields.ts +133 -0
- package/blocks/logo-cloud/index.ts +6 -0
- package/blocks/logo-cloud/schema.ts +46 -0
- package/blocks/post-content/component.tsx +197 -0
- package/blocks/post-content/config.ts +11 -0
- package/blocks/post-content/examples.ts +33 -0
- package/blocks/post-content/fields.ts +165 -0
- package/blocks/post-content/index.ts +4 -0
- package/blocks/post-content/schema.ts +46 -0
- package/blocks/pricing-table/component.tsx +154 -0
- package/blocks/pricing-table/config.ts +11 -0
- package/blocks/pricing-table/examples.ts +96 -0
- package/blocks/pricing-table/fields.ts +161 -0
- package/blocks/pricing-table/index.ts +4 -0
- package/blocks/pricing-table/schema.ts +50 -0
- package/blocks/split-content/component.tsx +135 -0
- package/blocks/split-content/config.ts +11 -0
- package/blocks/split-content/examples.ts +38 -0
- package/blocks/split-content/fields.ts +198 -0
- package/blocks/split-content/index.ts +6 -0
- package/blocks/split-content/schema.ts +67 -0
- package/blocks/stats-counter/component.tsx +124 -0
- package/blocks/stats-counter/config.ts +11 -0
- package/blocks/stats-counter/examples.ts +61 -0
- package/blocks/stats-counter/fields.ts +134 -0
- package/blocks/stats-counter/index.ts +6 -0
- package/blocks/stats-counter/schema.ts +47 -0
- package/blocks/testimonials/component.tsx +114 -0
- package/blocks/testimonials/config.ts +11 -0
- package/blocks/testimonials/examples.ts +65 -0
- package/blocks/testimonials/fields.ts +105 -0
- package/blocks/testimonials/index.ts +6 -0
- package/blocks/testimonials/schema.ts +41 -0
- package/blocks/testimonials/thumbnail.png +1 -0
- package/blocks/text-content/component.tsx +97 -0
- package/blocks/text-content/config.ts +11 -0
- package/blocks/text-content/examples.ts +30 -0
- package/blocks/text-content/fields.ts +88 -0
- package/blocks/text-content/index.ts +6 -0
- package/blocks/text-content/schema.ts +30 -0
- package/blocks/text-content/thumbnail.png +1 -0
- package/blocks/timeline/component.tsx +267 -0
- package/blocks/timeline/config.ts +11 -0
- package/blocks/timeline/examples.ts +68 -0
- package/blocks/timeline/fields.ts +147 -0
- package/blocks/timeline/index.ts +6 -0
- package/blocks/timeline/schema.ts +49 -0
- package/blocks/video-hero/component.tsx +270 -0
- package/blocks/video-hero/config.ts +11 -0
- package/blocks/video-hero/examples.ts +24 -0
- package/blocks/video-hero/fields.ts +98 -0
- package/blocks/video-hero/index.ts +6 -0
- package/blocks/video-hero/schema.ts +39 -0
- package/components/ai-chat/ChatPanel.tsx +575 -0
- package/components/ai-chat/ConversationItem.tsx +266 -0
- package/components/ai-chat/ConversationSidebar.tsx +99 -0
- package/components/ai-chat/MarkdownRenderer.tsx +15 -0
- package/components/ai-chat/Message.tsx +42 -0
- package/components/ai-chat/MessageInput.tsx +49 -0
- package/components/ai-chat/MessageList.tsx +46 -0
- package/components/ai-chat/TypingIndicator.tsx +11 -0
- package/config/app.config.ts +367 -0
- package/config/billing.config.ts +349 -0
- package/config/dashboard.config.ts +506 -0
- package/config/dev.config.ts +104 -0
- package/config/features.config.ts +203 -0
- package/config/flows.config.ts +129 -0
- package/config/permissions.config.ts +245 -0
- package/config/theme.config.ts +74 -0
- package/docs/01-overview/01-introduction.md +335 -0
- package/docs/01-overview/02-customization.md +671 -0
- package/docs/02-features/01-components.md +155 -0
- package/docs/02-features/02-styling.md +139 -0
- package/docs/02-features/03-tasks-entity.md +407 -0
- package/docs/03-ai/01-overview.md +211 -0
- package/docs/03-ai/02-customization.md +436 -0
- package/entities/customers/customers.config.ts +75 -0
- package/entities/customers/customers.fields.ts +165 -0
- package/entities/customers/customers.service.ts +516 -0
- package/entities/customers/customers.types.ts +83 -0
- package/entities/customers/messages/en.json +66 -0
- package/entities/customers/messages/es.json +66 -0
- package/entities/customers/migrations/001_customers_table.sql +102 -0
- package/entities/customers/migrations/002_customers_metas.sql +92 -0
- package/entities/pages/messages/en.json +41 -0
- package/entities/pages/messages/es.json +41 -0
- package/entities/pages/migrations/001_pages_table.sql +112 -0
- package/entities/pages/migrations/002_pages_metas.sql +56 -0
- package/entities/pages/migrations/003_add_status.sql +50 -0
- package/entities/pages/pages-management.service.ts +610 -0
- package/entities/pages/pages.config.ts +94 -0
- package/entities/pages/pages.fields.ts +101 -0
- package/entities/pages/pages.service.ts +290 -0
- package/entities/pages/pages.types.ts +124 -0
- package/entities/posts/components/post-header.tsx +97 -0
- package/entities/posts/messages/en.json +55 -0
- package/entities/posts/messages/es.json +55 -0
- package/entities/posts/migrations/001_posts_table.sql +115 -0
- package/entities/posts/migrations/003_add_status.sql +44 -0
- package/entities/posts/migrations/004_entity_taxonomy_relations.sql +129 -0
- package/entities/posts/migrations/006_posts_metas.sql +56 -0
- package/entities/posts/posts.config.ts +101 -0
- package/entities/posts/posts.fields.ts +116 -0
- package/entities/posts/posts.service.ts +376 -0
- package/entities/posts/posts.types.ts +74 -0
- package/entities/tasks/messages/en.json +204 -0
- package/entities/tasks/messages/es.json +204 -0
- package/entities/tasks/migrations/001_tasks_table.sql +105 -0
- package/entities/tasks/migrations/002_task_metas.sql +85 -0
- package/entities/tasks/migrations/sample_data.json +77 -0
- package/entities/tasks/tasks.config.ts +79 -0
- package/entities/tasks/tasks.fields.ts +196 -0
- package/entities/tasks/tasks.service.ts +541 -0
- package/entities/tasks/tasks.types.ts +56 -0
- package/lib/hooks/useAiChat.ts +114 -0
- package/lib/hooks/useConversations.ts +376 -0
- package/lib/hooks/useOrchestratorChat.ts +122 -0
- package/lib/hooks/usePersistentChat.ts +315 -0
- package/lib/hooks/useStreamingChat.ts +127 -0
- package/lib/hooks/useTokenUsage.ts +63 -0
- package/lib/langchain/agents/customer-assistant.md +69 -0
- package/lib/langchain/agents/index.ts +61 -0
- package/lib/langchain/agents/orchestrator.md +59 -0
- package/lib/langchain/agents/page-assistant.md +85 -0
- package/lib/langchain/agents/single-agent.md +46 -0
- package/lib/langchain/agents/task-assistant.md +55 -0
- package/lib/langchain/config.ts +45 -0
- package/lib/langchain/handlers/customer-handler.ts +338 -0
- package/lib/langchain/handlers/page-handler.ts +232 -0
- package/lib/langchain/handlers/task-handler.ts +323 -0
- package/lib/langchain/langchain.config.ts +223 -0
- package/lib/langchain/observability.config.ts +30 -0
- package/lib/langchain/orchestrator.ts +562 -0
- package/lib/langchain/tools/customers.ts +176 -0
- package/lib/langchain/tools/index.ts +10 -0
- package/lib/langchain/tools/orchestrator.ts +92 -0
- package/lib/langchain/tools/pages.ts +289 -0
- package/lib/langchain/tools/tasks.ts +167 -0
- package/lib/scheduled-actions/billing.ts +149 -0
- package/lib/scheduled-actions/index.ts +170 -0
- package/lib/scheduled-actions/webhook.ts +231 -0
- package/lib/selectors.ts +197 -0
- package/messages/de/admin.json +219 -0
- package/messages/de/aiUsage.json +36 -0
- package/messages/de/buttons.json +19 -0
- package/messages/de/categories.json +35 -0
- package/messages/de/common.json +16 -0
- package/messages/de/dev.json +101 -0
- package/messages/de/docs.json +27 -0
- package/messages/de/entities.json +7 -0
- package/messages/de/features.json +119 -0
- package/messages/de/footer.json +22 -0
- package/messages/de/home.json +57 -0
- package/messages/de/index.ts +39 -0
- package/messages/de/mobileNav.json +13 -0
- package/messages/de/navigation.json +8 -0
- package/messages/de/observability.json +74 -0
- package/messages/de/posts.json +54 -0
- package/messages/de/pricing.json +102 -0
- package/messages/de/support.json +9 -0
- package/messages/de/teams.json +8 -0
- package/messages/en/admin.json +219 -0
- package/messages/en/aiUsage.json +36 -0
- package/messages/en/buttons.json +19 -0
- package/messages/en/categories.json +35 -0
- package/messages/en/common.json +16 -0
- package/messages/en/dev.json +106 -0
- package/messages/en/docs.json +27 -0
- package/messages/en/entities.json +7 -0
- package/messages/en/features.json +119 -0
- package/messages/en/footer.json +22 -0
- package/messages/en/home.json +57 -0
- package/messages/en/index.ts +39 -0
- package/messages/en/mobileNav.json +13 -0
- package/messages/en/navigation.json +8 -0
- package/messages/en/observability.json +74 -0
- package/messages/en/posts.json +54 -0
- package/messages/en/pricing.json +102 -0
- package/messages/en/support.json +9 -0
- package/messages/en/teams.json +8 -0
- package/messages/es/admin.json +219 -0
- package/messages/es/aiUsage.json +36 -0
- package/messages/es/buttons.json +19 -0
- package/messages/es/categories.json +35 -0
- package/messages/es/common.json +16 -0
- package/messages/es/dev.json +101 -0
- package/messages/es/docs.json +27 -0
- package/messages/es/entities.json +7 -0
- package/messages/es/features.json +119 -0
- package/messages/es/footer.json +22 -0
- package/messages/es/home.json +57 -0
- package/messages/es/index.ts +39 -0
- package/messages/es/mobileNav.json +13 -0
- package/messages/es/navigation.json +8 -0
- package/messages/es/observability.json +74 -0
- package/messages/es/posts.json +54 -0
- package/messages/es/pricing.json +102 -0
- package/messages/es/support.json +9 -0
- package/messages/es/teams.json +8 -0
- package/messages/fr/admin.json +219 -0
- package/messages/fr/aiUsage.json +36 -0
- package/messages/fr/buttons.json +19 -0
- package/messages/fr/categories.json +35 -0
- package/messages/fr/common.json +16 -0
- package/messages/fr/dev.json +101 -0
- package/messages/fr/docs.json +27 -0
- package/messages/fr/entities.json +7 -0
- package/messages/fr/features.json +119 -0
- package/messages/fr/footer.json +22 -0
- package/messages/fr/home.json +57 -0
- package/messages/fr/index.ts +39 -0
- package/messages/fr/mobileNav.json +13 -0
- package/messages/fr/navigation.json +8 -0
- package/messages/fr/observability.json +74 -0
- package/messages/fr/posts.json +54 -0
- package/messages/fr/pricing.json +102 -0
- package/messages/fr/support.json +9 -0
- package/messages/fr/teams.json +8 -0
- package/messages/it/admin.json +219 -0
- package/messages/it/aiUsage.json +36 -0
- package/messages/it/buttons.json +19 -0
- package/messages/it/categories.json +35 -0
- package/messages/it/common.json +16 -0
- package/messages/it/dev.json +101 -0
- package/messages/it/docs.json +27 -0
- package/messages/it/entities.json +7 -0
- package/messages/it/features.json +119 -0
- package/messages/it/footer.json +22 -0
- package/messages/it/home.json +57 -0
- package/messages/it/index.ts +39 -0
- package/messages/it/mobileNav.json +13 -0
- package/messages/it/navigation.json +8 -0
- package/messages/it/observability.json +74 -0
- package/messages/it/posts.json +54 -0
- package/messages/it/pricing.json +102 -0
- package/messages/it/support.json +9 -0
- package/messages/it/teams.json +8 -0
- package/messages/pt/admin.json +219 -0
- package/messages/pt/aiUsage.json +36 -0
- package/messages/pt/buttons.json +19 -0
- package/messages/pt/categories.json +35 -0
- package/messages/pt/common.json +16 -0
- package/messages/pt/dev.json +101 -0
- package/messages/pt/docs.json +27 -0
- package/messages/pt/entities.json +7 -0
- package/messages/pt/features.json +119 -0
- package/messages/pt/footer.json +22 -0
- package/messages/pt/home.json +57 -0
- package/messages/pt/index.ts +39 -0
- package/messages/pt/mobileNav.json +13 -0
- package/messages/pt/navigation.json +8 -0
- package/messages/pt/observability.json +74 -0
- package/messages/pt/posts.json +54 -0
- package/messages/pt/pricing.json +102 -0
- package/messages/pt/support.json +9 -0
- package/messages/pt/teams.json +8 -0
- package/migrations/089_add_editor_team_role.sql +39 -0
- package/migrations/090_demo_users_teams.sql +540 -0
- package/migrations/091_greek_teams_billing.sql +523 -0
- package/migrations/092_billing_sample_data.sql +774 -0
- package/migrations/093_pages_sample_data.sql +1158 -0
- package/migrations/094_posts_sample_data.sql +278 -0
- package/migrations/095_tasks_sample_data.sql +440 -0
- package/migrations/096_customers_sample_data.sql +358 -0
- package/migrations/097_scheduled_actions_sample_data.sql +111 -0
- package/package.json +22 -0
- package/public/docs/desktop-layout-example.png +0 -0
- package/styles/components.css +11 -0
- package/styles/globals.css +179 -0
- package/templates/(public)/blog/[slug]/page.tsx +65 -0
- package/templates/(public)/layout.tsx +25 -0
- package/templates/(public)/page.tsx +200 -0
- package/templates/(public)/support/page.tsx +321 -0
- package/templates/dashboard/(main)/agent-multi/page.tsx +63 -0
- package/templates/dashboard/(main)/agent-single/page.tsx +142 -0
- package/templates/dashboard/(main)/settings/ai-usage/page.tsx +157 -0
- package/templates/superadmin/ai-observability/[traceId]/page.tsx +27 -0
- 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,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
|
+
]
|