@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,61 @@
|
|
|
1
|
+
import type { BlockExample } from '@nextsparkjs/core/types/blocks'
|
|
2
|
+
|
|
3
|
+
export const examples: BlockExample[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'Light Background',
|
|
6
|
+
description: 'Stats counter with light background',
|
|
7
|
+
props: {
|
|
8
|
+
title: 'Trusted by Thousands',
|
|
9
|
+
content: 'Join a growing community of successful businesses',
|
|
10
|
+
backgroundColor: 'gray-50',
|
|
11
|
+
stats: [
|
|
12
|
+
{
|
|
13
|
+
value: '10,000+',
|
|
14
|
+
label: 'Active Users',
|
|
15
|
+
description: 'Growing daily',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
value: '99.9%',
|
|
19
|
+
label: 'Uptime',
|
|
20
|
+
description: 'Reliable service',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: '50M+',
|
|
24
|
+
label: 'API Requests',
|
|
25
|
+
description: 'Processed monthly',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: '4.9/5',
|
|
29
|
+
label: 'Customer Rating',
|
|
30
|
+
description: 'From 2,000+ reviews',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'Dark Background',
|
|
37
|
+
description: 'Stats counter with dark background',
|
|
38
|
+
props: {
|
|
39
|
+
title: 'The Numbers Speak',
|
|
40
|
+
content: 'Real results from real customers',
|
|
41
|
+
backgroundColor: 'gray-900',
|
|
42
|
+
stats: [
|
|
43
|
+
{
|
|
44
|
+
value: '$2.5M+',
|
|
45
|
+
label: 'Revenue Generated',
|
|
46
|
+
description: 'For our customers',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
value: '150+',
|
|
50
|
+
label: 'Countries',
|
|
51
|
+
description: 'Worldwide reach',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
value: '24/7',
|
|
55
|
+
label: 'Support',
|
|
56
|
+
description: 'Always available',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
]
|
|
@@ -0,0 +1,134 @@
|
|
|
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
|
+
* Stats Counter Block Field Definitions
|
|
10
|
+
*
|
|
11
|
+
* Organized into 3 tabs:
|
|
12
|
+
* - Content: title, content, cta (from base) + stats array
|
|
13
|
+
* - Design: backgroundColor (from base) + columns, variant, size
|
|
14
|
+
* - Advanced: className, id (from base)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// Stats-specific content fields
|
|
18
|
+
const statsContentFields: FieldDefinition[] = [
|
|
19
|
+
{
|
|
20
|
+
name: 'stats',
|
|
21
|
+
label: 'Statistics',
|
|
22
|
+
type: 'array',
|
|
23
|
+
tab: 'content',
|
|
24
|
+
required: true,
|
|
25
|
+
description: 'List of statistics to display',
|
|
26
|
+
helpText: 'Add up to 8 statistics with values and labels',
|
|
27
|
+
minItems: 1,
|
|
28
|
+
maxItems: 8,
|
|
29
|
+
itemFields: [
|
|
30
|
+
{
|
|
31
|
+
name: 'value',
|
|
32
|
+
label: 'Value',
|
|
33
|
+
type: 'text',
|
|
34
|
+
tab: 'content',
|
|
35
|
+
required: true,
|
|
36
|
+
placeholder: '10,000+',
|
|
37
|
+
helpText: 'The number or metric value (e.g., "10,000+", "99%", "$1M+")',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'label',
|
|
41
|
+
label: 'Label',
|
|
42
|
+
type: 'text',
|
|
43
|
+
tab: 'content',
|
|
44
|
+
required: true,
|
|
45
|
+
placeholder: 'Happy Customers',
|
|
46
|
+
helpText: 'Description of the statistic',
|
|
47
|
+
maxLength: 100,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'prefix',
|
|
51
|
+
label: 'Prefix',
|
|
52
|
+
type: 'text',
|
|
53
|
+
tab: 'content',
|
|
54
|
+
required: false,
|
|
55
|
+
placeholder: '$',
|
|
56
|
+
helpText: 'Optional prefix (e.g., "$", "+")',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'suffix',
|
|
60
|
+
label: 'Suffix',
|
|
61
|
+
type: 'text',
|
|
62
|
+
tab: 'content',
|
|
63
|
+
required: false,
|
|
64
|
+
placeholder: '+',
|
|
65
|
+
helpText: 'Optional suffix (e.g., "%", "+", "K")',
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
// Stats-specific design fields
|
|
72
|
+
const statsDesignFields: FieldDefinition[] = [
|
|
73
|
+
{
|
|
74
|
+
name: 'columns',
|
|
75
|
+
label: 'Grid Columns',
|
|
76
|
+
type: 'select',
|
|
77
|
+
tab: 'design',
|
|
78
|
+
required: false,
|
|
79
|
+
default: '4',
|
|
80
|
+
description: 'Number of columns in the grid layout',
|
|
81
|
+
options: [
|
|
82
|
+
{ label: '2 Columns', value: '2' },
|
|
83
|
+
{ label: '3 Columns', value: '3' },
|
|
84
|
+
{ label: '4 Columns', value: '4' },
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'variant',
|
|
89
|
+
label: 'Style Variant',
|
|
90
|
+
type: 'select',
|
|
91
|
+
tab: 'design',
|
|
92
|
+
required: false,
|
|
93
|
+
default: 'default',
|
|
94
|
+
description: 'Visual style of the statistics',
|
|
95
|
+
options: [
|
|
96
|
+
{ label: 'Default', value: 'default' },
|
|
97
|
+
{ label: 'Cards (with background)', value: 'cards' },
|
|
98
|
+
{ label: 'Minimal (text only)', value: 'minimal' },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'size',
|
|
103
|
+
label: 'Number Size',
|
|
104
|
+
type: 'select',
|
|
105
|
+
tab: 'design',
|
|
106
|
+
required: false,
|
|
107
|
+
default: 'md',
|
|
108
|
+
description: 'Size of the statistic numbers',
|
|
109
|
+
options: [
|
|
110
|
+
{ label: 'Small', value: 'sm' },
|
|
111
|
+
{ label: 'Medium', value: 'md' },
|
|
112
|
+
{ label: 'Large', value: 'lg' },
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Complete field definitions organized by tab
|
|
119
|
+
*/
|
|
120
|
+
export const fieldDefinitions: FieldDefinition[] = [
|
|
121
|
+
// Content tab: base fields + stats-specific
|
|
122
|
+
...baseContentFields,
|
|
123
|
+
...statsContentFields,
|
|
124
|
+
|
|
125
|
+
// Design tab: base fields + stats-specific
|
|
126
|
+
...baseDesignFields,
|
|
127
|
+
...statsDesignFields,
|
|
128
|
+
|
|
129
|
+
// Advanced tab: base fields only
|
|
130
|
+
...baseAdvancedFields,
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
// Alias for compatibility
|
|
134
|
+
export const fields = fieldDefinitions
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { baseBlockSchema } from '@nextsparkjs/core/types/blocks'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Stat Item Schema
|
|
6
|
+
* Individual statistic with value, label, and optional prefix/suffix
|
|
7
|
+
*/
|
|
8
|
+
const statItemSchema = z.object({
|
|
9
|
+
value: z.string().min(1, 'Value is required'),
|
|
10
|
+
label: z.string().min(1, 'Label is required').max(100),
|
|
11
|
+
prefix: z.string().optional(),
|
|
12
|
+
suffix: z.string().optional(),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export type StatItem = z.infer<typeof statItemSchema>
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Stats Counter Block Schema
|
|
19
|
+
*
|
|
20
|
+
* Extends base schema with:
|
|
21
|
+
* - stats: Array of statistics (value, label, prefix, suffix)
|
|
22
|
+
* - columns: Grid layout option (2, 3, 4 columns)
|
|
23
|
+
* - variant: Visual style (default, cards, minimal)
|
|
24
|
+
* - size: Number size (sm, md, lg)
|
|
25
|
+
*
|
|
26
|
+
* Note: Uses base schema title, content, cta, backgroundColor, className, id
|
|
27
|
+
* The `title` field serves as optional section title
|
|
28
|
+
* The `content` field serves as optional section description/subtitle
|
|
29
|
+
*/
|
|
30
|
+
export const statsCounterSpecificSchema = z.object({
|
|
31
|
+
// Content: array of stat items
|
|
32
|
+
stats: z.array(statItemSchema)
|
|
33
|
+
.min(1, 'At least one statistic is required')
|
|
34
|
+
.max(8, 'Maximum 8 statistics allowed'),
|
|
35
|
+
|
|
36
|
+
// Design: visual appearance
|
|
37
|
+
columns: z.enum(['2', '3', '4']).default('4'),
|
|
38
|
+
variant: z.enum(['default', 'cards', 'minimal']).default('default'),
|
|
39
|
+
size: z.enum(['sm', 'md', 'lg']).default('md'),
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Complete Stats Counter Block Schema
|
|
44
|
+
*/
|
|
45
|
+
export const schema = baseBlockSchema.merge(statsCounterSpecificSchema)
|
|
46
|
+
|
|
47
|
+
export type StatsCounterBlockProps = z.infer<typeof schema>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Quote } from 'lucide-react'
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from '@nextsparkjs/core/components/ui/avatar'
|
|
4
|
+
import { cn } from '@nextsparkjs/core/lib/utils'
|
|
5
|
+
import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
|
|
6
|
+
import { sel } from '../../lib/selectors'
|
|
7
|
+
import type { TestimonialsBlockProps, TestimonialItem } from './schema'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Testimonials Block Component
|
|
11
|
+
*
|
|
12
|
+
* Props from 3-tab structure:
|
|
13
|
+
* - Content: title, content, cta, items
|
|
14
|
+
* - Design: backgroundColor, columns
|
|
15
|
+
* - Advanced: className, id
|
|
16
|
+
*/
|
|
17
|
+
export function TestimonialsBlock({
|
|
18
|
+
// Base content props
|
|
19
|
+
title,
|
|
20
|
+
content,
|
|
21
|
+
cta,
|
|
22
|
+
// Testimonials-specific content
|
|
23
|
+
items,
|
|
24
|
+
// Base design props
|
|
25
|
+
backgroundColor = 'gray-50',
|
|
26
|
+
// Testimonials-specific design
|
|
27
|
+
columns = '3',
|
|
28
|
+
// Base advanced props
|
|
29
|
+
className,
|
|
30
|
+
id,
|
|
31
|
+
}: TestimonialsBlockProps) {
|
|
32
|
+
// Build column classes based on columns prop
|
|
33
|
+
const columnClasses: Record<string, string> = {
|
|
34
|
+
'2': 'md:grid-cols-2',
|
|
35
|
+
'3': 'md:grid-cols-2 lg:grid-cols-3',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Build section classes with background and custom className
|
|
39
|
+
const sectionClasses = buildSectionClasses(
|
|
40
|
+
'py-16 px-4 md:py-24',
|
|
41
|
+
{ backgroundColor, className }
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
// Ensure items is always an array
|
|
45
|
+
const safeItems = Array.isArray(items) ? items : []
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<section id={id} className={sectionClasses} data-cy={sel('blocks.testimonials.container')}>
|
|
49
|
+
<div className="container mx-auto max-w-6xl">
|
|
50
|
+
{/* Section Header */}
|
|
51
|
+
{(title || content) && (
|
|
52
|
+
<div className="mb-12 text-center">
|
|
53
|
+
{title && (
|
|
54
|
+
<h2 className="mb-4 text-4xl font-bold md:text-5xl">
|
|
55
|
+
{title}
|
|
56
|
+
</h2>
|
|
57
|
+
)}
|
|
58
|
+
{content && (
|
|
59
|
+
<p className="mx-auto max-w-2xl text-lg text-muted-foreground">
|
|
60
|
+
{content}
|
|
61
|
+
</p>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
{/* Testimonials Grid */}
|
|
67
|
+
<div className={cn('grid gap-8', columnClasses[columns] || columnClasses['3'])}>
|
|
68
|
+
{safeItems.map((item: TestimonialItem, index: number) => (
|
|
69
|
+
<div
|
|
70
|
+
key={index}
|
|
71
|
+
className="flex flex-col p-6 rounded-lg border bg-card"
|
|
72
|
+
>
|
|
73
|
+
<Quote className="h-8 w-8 text-primary mb-4" />
|
|
74
|
+
|
|
75
|
+
<blockquote className="mb-6 text-lg flex-grow">
|
|
76
|
+
"{item.quote}"
|
|
77
|
+
</blockquote>
|
|
78
|
+
|
|
79
|
+
<div className="flex items-center gap-3">
|
|
80
|
+
<Avatar>
|
|
81
|
+
<AvatarImage src={item.avatar} alt={item.author} />
|
|
82
|
+
<AvatarFallback>
|
|
83
|
+
{item.author.split(' ').map((n: string) => n[0]).join('')}
|
|
84
|
+
</AvatarFallback>
|
|
85
|
+
</Avatar>
|
|
86
|
+
|
|
87
|
+
<div>
|
|
88
|
+
<div className="font-semibold">{item.author}</div>
|
|
89
|
+
{item.role && (
|
|
90
|
+
<div className="text-sm text-muted-foreground">{item.role}</div>
|
|
91
|
+
)}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
))}
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
{/* Optional CTA */}
|
|
99
|
+
{cta && (
|
|
100
|
+
<div className="mt-12 text-center">
|
|
101
|
+
<a
|
|
102
|
+
href={cta.link}
|
|
103
|
+
target={cta.target}
|
|
104
|
+
rel={cta.target === '_blank' ? 'noopener noreferrer' : undefined}
|
|
105
|
+
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"
|
|
106
|
+
>
|
|
107
|
+
{cta.text}
|
|
108
|
+
</a>
|
|
109
|
+
</div>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
</section>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
@@ -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: 'testimonials',
|
|
5
|
+
name: 'Testimonials',
|
|
6
|
+
description: 'Display customer testimonials with quotes, authors, and avatars',
|
|
7
|
+
category: 'testimonials',
|
|
8
|
+
icon: 'Quote',
|
|
9
|
+
thumbnail: '/theme/blocks/testimonials/thumbnail.png',
|
|
10
|
+
scope: ['pages']
|
|
11
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { BlockExample } from '@nextsparkjs/core/types/blocks'
|
|
2
|
+
|
|
3
|
+
export const examples: BlockExample[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'Grid',
|
|
6
|
+
description: 'Testimonials in grid layout',
|
|
7
|
+
props: {
|
|
8
|
+
title: 'What Our Customers Say',
|
|
9
|
+
content: 'Hear from teams who transformed their workflow',
|
|
10
|
+
backgroundColor: 'white',
|
|
11
|
+
layout: 'grid',
|
|
12
|
+
showImages: true,
|
|
13
|
+
testimonials: [
|
|
14
|
+
{
|
|
15
|
+
quote: 'This platform completely changed how we work. The automation features alone save us 10+ hours per week.',
|
|
16
|
+
author: 'Sarah Johnson',
|
|
17
|
+
role: 'VP of Operations',
|
|
18
|
+
company: 'TechCorp',
|
|
19
|
+
image: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
quote: 'Best investment we made this year. The ROI was clear within the first month of use.',
|
|
23
|
+
author: 'Michael Chen',
|
|
24
|
+
role: 'CTO',
|
|
25
|
+
company: 'StartupXYZ',
|
|
26
|
+
image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
quote: 'The support team is incredible. They helped us migrate all our data seamlessly.',
|
|
30
|
+
author: 'Emily Rodriguez',
|
|
31
|
+
role: 'Product Manager',
|
|
32
|
+
company: 'InnovateLabs',
|
|
33
|
+
image: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=400',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Carousel',
|
|
40
|
+
description: 'Testimonials in carousel format',
|
|
41
|
+
props: {
|
|
42
|
+
title: 'Customer Success Stories',
|
|
43
|
+
backgroundColor: 'gray-50',
|
|
44
|
+
layout: 'carousel',
|
|
45
|
+
showImages: true,
|
|
46
|
+
autoplay: true,
|
|
47
|
+
testimonials: [
|
|
48
|
+
{
|
|
49
|
+
quote: 'We tried several platforms before finding this one. It is exactly what we needed - powerful yet simple to use.',
|
|
50
|
+
author: 'David Park',
|
|
51
|
+
role: 'CEO',
|
|
52
|
+
company: 'GrowthCo',
|
|
53
|
+
image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
quote: 'The analytics dashboard gives us insights we never had before. Game changer for our team.',
|
|
57
|
+
author: 'Lisa Thompson',
|
|
58
|
+
role: 'Marketing Director',
|
|
59
|
+
company: 'BrandBuilder',
|
|
60
|
+
image: 'https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?w=400',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
]
|
|
@@ -0,0 +1,105 @@
|
|
|
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
|
+
* Testimonials 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
|
+
// Testimonials-specific content fields
|
|
18
|
+
const testimonialsContentFields: FieldDefinition[] = [
|
|
19
|
+
{
|
|
20
|
+
name: 'items',
|
|
21
|
+
label: 'Testimonials',
|
|
22
|
+
type: 'array',
|
|
23
|
+
tab: 'content',
|
|
24
|
+
required: true,
|
|
25
|
+
description: 'Customer testimonials to display',
|
|
26
|
+
helpText: 'Add up to 6 testimonials',
|
|
27
|
+
minItems: 1,
|
|
28
|
+
maxItems: 6,
|
|
29
|
+
itemFields: [
|
|
30
|
+
{
|
|
31
|
+
name: 'quote',
|
|
32
|
+
label: 'Quote',
|
|
33
|
+
type: 'textarea',
|
|
34
|
+
tab: 'content',
|
|
35
|
+
required: true,
|
|
36
|
+
placeholder: 'This product changed my life...',
|
|
37
|
+
maxLength: 500,
|
|
38
|
+
rows: 3,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'author',
|
|
42
|
+
label: 'Author Name',
|
|
43
|
+
type: 'text',
|
|
44
|
+
tab: 'content',
|
|
45
|
+
required: true,
|
|
46
|
+
placeholder: 'John Doe',
|
|
47
|
+
maxLength: 100,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'role',
|
|
51
|
+
label: 'Role/Title',
|
|
52
|
+
type: 'text',
|
|
53
|
+
tab: 'content',
|
|
54
|
+
required: false,
|
|
55
|
+
placeholder: 'CEO at Company',
|
|
56
|
+
maxLength: 100,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'avatar',
|
|
60
|
+
label: 'Avatar Image',
|
|
61
|
+
type: 'image',
|
|
62
|
+
tab: 'content',
|
|
63
|
+
required: false,
|
|
64
|
+
description: 'Profile picture of the person',
|
|
65
|
+
helpText: 'Recommended size: 100x100px',
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
// Testimonials-specific design fields
|
|
72
|
+
const testimonialsDesignFields: FieldDefinition[] = [
|
|
73
|
+
{
|
|
74
|
+
name: 'columns',
|
|
75
|
+
label: 'Grid Columns',
|
|
76
|
+
type: 'select',
|
|
77
|
+
tab: 'design',
|
|
78
|
+
required: false,
|
|
79
|
+
default: '3',
|
|
80
|
+
description: 'Number of columns in the grid layout',
|
|
81
|
+
options: [
|
|
82
|
+
{ label: '2 Columns', value: '2' },
|
|
83
|
+
{ label: '3 Columns', value: '3' },
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Complete field definitions organized by tab
|
|
90
|
+
*/
|
|
91
|
+
export const fieldDefinitions: FieldDefinition[] = [
|
|
92
|
+
// Content tab: base fields + testimonials-specific
|
|
93
|
+
...baseContentFields,
|
|
94
|
+
...testimonialsContentFields,
|
|
95
|
+
|
|
96
|
+
// Design tab: base fields + testimonials-specific
|
|
97
|
+
...baseDesignFields,
|
|
98
|
+
...testimonialsDesignFields,
|
|
99
|
+
|
|
100
|
+
// Advanced tab: base fields only
|
|
101
|
+
...baseAdvancedFields,
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
// Alias for compatibility
|
|
105
|
+
export const fields = fieldDefinitions
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { baseBlockSchema } from '@nextsparkjs/core/types/blocks'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Testimonial Item Schema
|
|
6
|
+
* Individual testimonial entry
|
|
7
|
+
*/
|
|
8
|
+
const testimonialItemSchema = z.object({
|
|
9
|
+
quote: z.string().min(1, 'Quote is required').max(500),
|
|
10
|
+
author: z.string().min(1, 'Author name is required').max(100),
|
|
11
|
+
role: z.string().max(100).optional(),
|
|
12
|
+
avatar: z.string().url('Must be a valid URL').optional(),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export type TestimonialItem = z.infer<typeof testimonialItemSchema>
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Testimonials Block Schema
|
|
19
|
+
*
|
|
20
|
+
* Extends base schema with:
|
|
21
|
+
* - items: Array of testimonial items
|
|
22
|
+
* - columns: Grid layout option (2, 3 columns)
|
|
23
|
+
*
|
|
24
|
+
* Note: Uses base schema title, description, cta, backgroundColor, className, id
|
|
25
|
+
*/
|
|
26
|
+
export const testimonialsSpecificSchema = z.object({
|
|
27
|
+
// Content: array of testimonials
|
|
28
|
+
items: z.array(testimonialItemSchema)
|
|
29
|
+
.min(1, 'At least one testimonial is required')
|
|
30
|
+
.max(6, 'Maximum 6 testimonials allowed'),
|
|
31
|
+
|
|
32
|
+
// Design: column layout
|
|
33
|
+
columns: z.enum(['2', '3']).default('3'),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Complete Testimonials Block Schema
|
|
38
|
+
*/
|
|
39
|
+
export const schema = baseBlockSchema.merge(testimonialsSpecificSchema)
|
|
40
|
+
|
|
41
|
+
export type TestimonialsBlockProps = z.infer<typeof schema>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Placeholder
|