@contractspec/bundle.marketing 3.7.6 → 3.7.7

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 (163) hide show
  1. package/.turbo/turbo-build.log +84 -84
  2. package/AGENTS.md +29 -21
  3. package/README.md +36 -49
  4. package/dist/browser/components/marketing/ChangelogPage.js +8 -8
  5. package/dist/browser/components/marketing/CofounderPage.js +167 -523
  6. package/dist/browser/components/marketing/ContactClient.js +200 -207
  7. package/dist/browser/components/marketing/ContributePage.js +211 -463
  8. package/dist/browser/components/marketing/DesignPartnerPage.js +165 -218
  9. package/dist/browser/components/marketing/LandingPage.js +464 -568
  10. package/dist/browser/components/marketing/PricingClient.js +213 -839
  11. package/dist/browser/components/marketing/ProductClientPage.js +265 -463
  12. package/dist/browser/components/marketing/index.js +2007 -3338
  13. package/dist/browser/components/marketing/pricing-thinking-modal.js +12 -12
  14. package/dist/browser/components/marketing/sections/AudienceSection.js +2 -2
  15. package/dist/browser/components/marketing/sections/CorePositioningSection.js +2 -2
  16. package/dist/browser/components/marketing/sections/CtaSection.js +3 -3
  17. package/dist/browser/components/marketing/sections/FearsSection.js +3 -3
  18. package/dist/browser/components/marketing/sections/HeroMarketingSection.js +6 -6
  19. package/dist/browser/components/marketing/sections/IconGridSection.js +2 -2
  20. package/dist/browser/components/marketing/sections/OutputsSection.js +2 -2
  21. package/dist/browser/components/marketing/sections/ProblemSection.js +2 -2
  22. package/dist/browser/components/marketing/sections/SolutionSection.js +2 -2
  23. package/dist/browser/components/marketing/sections/StepsSection.js +4 -4
  24. package/dist/browser/components/marketing/studio-signup-section.js +25 -41
  25. package/dist/browser/components/templates/TemplatesClientPage.js +2324 -3578
  26. package/dist/browser/components/templates/TemplatesPage.js +1 -1
  27. package/dist/browser/components/templates/TemplatesPreviewModal.js +3 -3
  28. package/dist/browser/components/templates/index.js +2361 -3615
  29. package/dist/browser/index.js +2363 -3617
  30. package/dist/browser/libs/email/client.js +1 -1
  31. package/dist/browser/libs/email/contact.js +1 -1
  32. package/dist/browser/libs/email/newsletter.js +1 -1
  33. package/dist/browser/libs/email/waitlist-application.js +1 -1
  34. package/dist/browser/libs/email/waitlist.js +1 -1
  35. package/dist/browser/registry/engine.js +2003 -3334
  36. package/dist/browser/registry/index.js +2003 -3334
  37. package/dist/browser/registry/registry-docs.js +2 -2
  38. package/dist/browser/registry/registry-landing.js +2007 -3338
  39. package/dist/browser/registry/registry.js +2003 -3334
  40. package/dist/browser/registry/utils.js +2003 -3334
  41. package/dist/components/marketing/ChangelogPage.js +8 -8
  42. package/dist/components/marketing/CofounderPage.js +167 -523
  43. package/dist/components/marketing/ContactClient.js +200 -207
  44. package/dist/components/marketing/ContributePage.d.ts +0 -2
  45. package/dist/components/marketing/ContributePage.js +211 -463
  46. package/dist/components/marketing/DesignPartnerPage.js +165 -218
  47. package/dist/components/marketing/LandingPage.js +464 -568
  48. package/dist/components/marketing/PricingClient.js +213 -839
  49. package/dist/components/marketing/ProductClientPage.js +265 -463
  50. package/dist/components/marketing/index.d.ts +5 -5
  51. package/dist/components/marketing/index.js +2007 -3338
  52. package/dist/components/marketing/pricing-thinking-modal.js +12 -12
  53. package/dist/components/marketing/sections/AudienceSection.js +2 -2
  54. package/dist/components/marketing/sections/CorePositioningSection.js +2 -2
  55. package/dist/components/marketing/sections/CtaSection.js +3 -3
  56. package/dist/components/marketing/sections/FearsSection.js +3 -3
  57. package/dist/components/marketing/sections/HeroMarketingSection.js +6 -6
  58. package/dist/components/marketing/sections/IconGridSection.d.ts +3 -3
  59. package/dist/components/marketing/sections/IconGridSection.js +2 -2
  60. package/dist/components/marketing/sections/OutputsSection.js +2 -2
  61. package/dist/components/marketing/sections/ProblemSection.js +2 -2
  62. package/dist/components/marketing/sections/SolutionSection.js +2 -2
  63. package/dist/components/marketing/sections/StepsSection.js +4 -4
  64. package/dist/components/marketing/studio-signup-section.js +25 -41
  65. package/dist/components/templates/TemplatesClientPage.js +2324 -3578
  66. package/dist/components/templates/TemplatesPage.js +1 -1
  67. package/dist/components/templates/TemplatesPreviewModal.js +3 -3
  68. package/dist/components/templates/index.js +2361 -3615
  69. package/dist/index.js +2363 -3617
  70. package/dist/libs/email/client.js +1 -1
  71. package/dist/libs/email/contact.js +1 -1
  72. package/dist/libs/email/newsletter.js +1 -1
  73. package/dist/libs/email/waitlist-application.js +1 -1
  74. package/dist/libs/email/waitlist.js +1 -1
  75. package/dist/node/components/marketing/ChangelogPage.js +8 -8
  76. package/dist/node/components/marketing/CofounderPage.js +167 -523
  77. package/dist/node/components/marketing/ContactClient.js +200 -207
  78. package/dist/node/components/marketing/ContributePage.js +211 -463
  79. package/dist/node/components/marketing/DesignPartnerPage.js +165 -218
  80. package/dist/node/components/marketing/LandingPage.js +464 -568
  81. package/dist/node/components/marketing/PricingClient.js +213 -839
  82. package/dist/node/components/marketing/ProductClientPage.js +265 -463
  83. package/dist/node/components/marketing/index.js +2007 -3338
  84. package/dist/node/components/marketing/pricing-thinking-modal.js +12 -12
  85. package/dist/node/components/marketing/sections/AudienceSection.js +2 -2
  86. package/dist/node/components/marketing/sections/CorePositioningSection.js +2 -2
  87. package/dist/node/components/marketing/sections/CtaSection.js +3 -3
  88. package/dist/node/components/marketing/sections/FearsSection.js +3 -3
  89. package/dist/node/components/marketing/sections/HeroMarketingSection.js +6 -6
  90. package/dist/node/components/marketing/sections/IconGridSection.js +2 -2
  91. package/dist/node/components/marketing/sections/OutputsSection.js +2 -2
  92. package/dist/node/components/marketing/sections/ProblemSection.js +2 -2
  93. package/dist/node/components/marketing/sections/SolutionSection.js +2 -2
  94. package/dist/node/components/marketing/sections/StepsSection.js +4 -4
  95. package/dist/node/components/marketing/studio-signup-section.js +25 -41
  96. package/dist/node/components/templates/TemplatesClientPage.js +2324 -3578
  97. package/dist/node/components/templates/TemplatesPage.js +1 -1
  98. package/dist/node/components/templates/TemplatesPreviewModal.js +3 -3
  99. package/dist/node/components/templates/index.js +2361 -3615
  100. package/dist/node/index.js +2363 -3617
  101. package/dist/node/libs/email/client.js +1 -1
  102. package/dist/node/libs/email/contact.js +1 -1
  103. package/dist/node/libs/email/newsletter.js +1 -1
  104. package/dist/node/libs/email/waitlist-application.js +1 -1
  105. package/dist/node/libs/email/waitlist.js +1 -1
  106. package/dist/node/registry/engine.js +2003 -3334
  107. package/dist/node/registry/index.js +2003 -3334
  108. package/dist/node/registry/registry-docs.js +2 -2
  109. package/dist/node/registry/registry-landing.js +2007 -3338
  110. package/dist/node/registry/registry.js +2003 -3334
  111. package/dist/node/registry/utils.js +2003 -3334
  112. package/dist/registry/engine.js +2003 -3334
  113. package/dist/registry/index.js +2003 -3334
  114. package/dist/registry/registry-docs.js +2 -2
  115. package/dist/registry/registry-landing.js +2007 -3338
  116. package/dist/registry/registry.js +2003 -3334
  117. package/dist/registry/utils.js +2003 -3334
  118. package/package.json +22 -22
  119. package/src/bundles/MarketingBundle.ts +273 -273
  120. package/src/components/marketing/ChangelogPage.tsx +72 -100
  121. package/src/components/marketing/CofounderPage.tsx +120 -384
  122. package/src/components/marketing/ContactClient.tsx +164 -154
  123. package/src/components/marketing/ContributePage.tsx +139 -313
  124. package/src/components/marketing/DesignPartnerPage.tsx +133 -171
  125. package/src/components/marketing/LandingPage.tsx +353 -25
  126. package/src/components/marketing/PricingClient.tsx +192 -437
  127. package/src/components/marketing/ProductClientPage.tsx +255 -377
  128. package/src/components/marketing/index.ts +5 -5
  129. package/src/components/marketing/pricing-thinking-modal.tsx +197 -197
  130. package/src/components/marketing/sections/AudienceSection.tsx +55 -56
  131. package/src/components/marketing/sections/CorePositioningSection.tsx +37 -37
  132. package/src/components/marketing/sections/CtaSection.tsx +49 -50
  133. package/src/components/marketing/sections/DevelopersSection.tsx +26 -27
  134. package/src/components/marketing/sections/FearsSection.tsx +36 -37
  135. package/src/components/marketing/sections/HeroMarketingSection.tsx +59 -59
  136. package/src/components/marketing/sections/IconGridSection.tsx +71 -71
  137. package/src/components/marketing/sections/OutputsSection.tsx +51 -52
  138. package/src/components/marketing/sections/ProblemSection.tsx +39 -40
  139. package/src/components/marketing/sections/SolutionSection.tsx +39 -40
  140. package/src/components/marketing/sections/StepsSection.tsx +47 -48
  141. package/src/components/marketing/studio-signup-section.tsx +39 -41
  142. package/src/components/templates/TemplatesClientPage.tsx +727 -685
  143. package/src/components/templates/TemplatesPage.tsx +110 -110
  144. package/src/components/templates/TemplatesPreviewModal.tsx +197 -198
  145. package/src/index.ts +4 -4
  146. package/src/libs/email/client.test.ts +81 -81
  147. package/src/libs/email/client.ts +111 -111
  148. package/src/libs/email/contact.ts +35 -35
  149. package/src/libs/email/newsletter.ts +46 -46
  150. package/src/libs/email/types.ts +29 -29
  151. package/src/libs/email/utils.ts +5 -5
  152. package/src/libs/email/waitlist-application.ts +72 -72
  153. package/src/libs/email/waitlist.ts +46 -46
  154. package/src/libs/pricing-examples.ts +12 -12
  155. package/src/registry/engine.ts +16 -16
  156. package/src/registry/factory.ts +57 -57
  157. package/src/registry/registry-docs.ts +656 -666
  158. package/src/registry/registry-landing.ts +94 -95
  159. package/src/registry/registry.ts +36 -37
  160. package/src/registry/types.ts +2 -2
  161. package/src/registry/utils.ts +56 -56
  162. package/tsconfig.json +11 -11
  163. package/tsdown.config.js +5 -5
@@ -1,105 +1,104 @@
1
1
  'use client';
2
2
 
3
- import { useMemo } from 'react';
4
-
5
- import dynamic from 'next/dynamic';
3
+ import type { TemplateId } from '@contractspec/lib.example-shared-ui';
4
+ import { LoadingSpinner } from '@contractspec/lib.ui-kit-web/ui/atoms/LoadingSpinner';
6
5
  import { Dialog, DialogContent } from '@contractspec/lib.ui-kit-web/ui/dialog';
7
6
  import { ScrollArea } from '@contractspec/lib.ui-kit-web/ui/scroll-area';
8
- import { LoadingSpinner } from '@contractspec/lib.ui-kit-web/ui/atoms/LoadingSpinner';
9
- import type { TemplateId } from '@contractspec/lib.example-shared-ui';
7
+ import dynamic from 'next/dynamic';
8
+ import { useMemo } from 'react';
10
9
 
11
10
  // Dynamically import template components with ssr: false
12
11
  const TemplateShell = dynamic(
13
- () =>
14
- import('@contractspec/lib.example-shared-ui').then(
15
- (mod) => mod.TemplateShell
16
- ),
17
- { ssr: false, loading: () => <LoadingSpinner /> }
12
+ () =>
13
+ import('@contractspec/lib.example-shared-ui').then(
14
+ (mod) => mod.TemplateShell
15
+ ),
16
+ { ssr: false, loading: () => <LoadingSpinner /> }
18
17
  );
19
18
 
20
19
  const TodosTaskList = dynamic(
21
- () =>
22
- import('@contractspec/bundle.library/components/templates/todos/TaskList').then(
23
- (mod) => mod.TaskList
24
- ),
25
- { ssr: false, loading: () => <LoadingSpinner /> }
20
+ () =>
21
+ import(
22
+ '@contractspec/bundle.library/components/templates/todos/TaskList'
23
+ ).then((mod) => mod.TaskList),
24
+ { ssr: false, loading: () => <LoadingSpinner /> }
26
25
  );
27
26
 
28
27
  const MessagingWorkspace = dynamic(
29
- () =>
30
- import('@contractspec/bundle.library/components/templates/messaging/MessagingWorkspace').then(
31
- (mod) => mod.MessagingWorkspace
32
- ),
33
- { ssr: false, loading: () => <LoadingSpinner /> }
28
+ () =>
29
+ import(
30
+ '@contractspec/bundle.library/components/templates/messaging/MessagingWorkspace'
31
+ ).then((mod) => mod.MessagingWorkspace),
32
+ { ssr: false, loading: () => <LoadingSpinner /> }
34
33
  );
35
34
 
36
35
  const RecipesExperience = dynamic(
37
- () =>
38
- import('@contractspec/bundle.library/components/templates/recipes/RecipeList').then(
39
- (mod) => mod.RecipeList
40
- ),
41
- { ssr: false, loading: () => <LoadingSpinner /> }
36
+ () =>
37
+ import(
38
+ '@contractspec/bundle.library/components/templates/recipes/RecipeList'
39
+ ).then((mod) => mod.RecipeList),
40
+ { ssr: false, loading: () => <LoadingSpinner /> }
42
41
  );
43
42
 
44
43
  const SaasDashboard = dynamic(
45
- () =>
46
- import('@contractspec/example.saas-boilerplate').then(
47
- (mod) => mod.SaasDashboard
48
- ),
49
- { ssr: false, loading: () => <LoadingSpinner /> }
44
+ () =>
45
+ import('@contractspec/example.saas-boilerplate').then(
46
+ (mod) => mod.SaasDashboard
47
+ ),
48
+ { ssr: false, loading: () => <LoadingSpinner /> }
50
49
  );
51
50
 
52
51
  const CrmDashboard = dynamic(
53
- () =>
54
- import('@contractspec/example.crm-pipeline').then(
55
- (mod) => mod.CrmDashboard
56
- ),
57
- { ssr: false, loading: () => <LoadingSpinner /> }
52
+ () =>
53
+ import('@contractspec/example.crm-pipeline').then(
54
+ (mod) => mod.CrmDashboard
55
+ ),
56
+ { ssr: false, loading: () => <LoadingSpinner /> }
58
57
  );
59
58
 
60
59
  const AgentDashboard = dynamic(
61
- () =>
62
- import('@contractspec/example.agent-console/ui').then(
63
- (mod) => mod.AgentDashboard
64
- ),
65
- { ssr: false, loading: () => <LoadingSpinner /> }
60
+ () =>
61
+ import('@contractspec/example.agent-console/ui').then(
62
+ (mod) => mod.AgentDashboard
63
+ ),
64
+ { ssr: false, loading: () => <LoadingSpinner /> }
66
65
  );
67
66
 
68
67
  const WorkflowDashboard = dynamic(
69
- () =>
70
- import('@contractspec/example.workflow-system/ui').then(
71
- (mod) => mod.WorkflowDashboard
72
- ),
73
- { ssr: false, loading: () => <LoadingSpinner /> }
68
+ () =>
69
+ import('@contractspec/example.workflow-system/ui').then(
70
+ (mod) => mod.WorkflowDashboard
71
+ ),
72
+ { ssr: false, loading: () => <LoadingSpinner /> }
74
73
  );
75
74
 
76
75
  const MarketplaceDashboard = dynamic(
77
- () =>
78
- import('@contractspec/example.marketplace/ui').then(
79
- (mod) => mod.MarketplaceDashboard
80
- ),
81
- { ssr: false, loading: () => <LoadingSpinner /> }
76
+ () =>
77
+ import('@contractspec/example.marketplace/ui').then(
78
+ (mod) => mod.MarketplaceDashboard
79
+ ),
80
+ { ssr: false, loading: () => <LoadingSpinner /> }
82
81
  );
83
82
 
84
83
  const IntegrationDashboard = dynamic(
85
- () =>
86
- import('@contractspec/example.integration-hub/ui').then(
87
- (mod) => mod.IntegrationDashboard
88
- ),
89
- { ssr: false, loading: () => <LoadingSpinner /> }
84
+ () =>
85
+ import('@contractspec/example.integration-hub/ui').then(
86
+ (mod) => mod.IntegrationDashboard
87
+ ),
88
+ { ssr: false, loading: () => <LoadingSpinner /> }
90
89
  );
91
90
 
92
91
  const AnalyticsDashboard = dynamic(
93
- () =>
94
- import('@contractspec/example.analytics-dashboard').then(
95
- (mod) => mod.AnalyticsDashboard
96
- ),
97
- { ssr: false, loading: () => <LoadingSpinner /> }
92
+ () =>
93
+ import('@contractspec/example.analytics-dashboard').then(
94
+ (mod) => mod.AnalyticsDashboard
95
+ ),
96
+ { ssr: false, loading: () => <LoadingSpinner /> }
98
97
  );
99
98
 
100
99
  interface TemplatePreviewModalProps {
101
- templateId: TemplateId | null;
102
- onClose: () => void;
100
+ templateId: TemplateId | null;
101
+ onClose: () => void;
103
102
  }
104
103
  //
105
104
  // return (
@@ -119,142 +118,142 @@ interface TemplatePreviewModalProps {
119
118
  // };
120
119
 
121
120
  export const TemplatePreviewModal = ({
122
- templateId,
123
- onClose,
121
+ templateId,
122
+ onClose,
124
123
  }: TemplatePreviewModalProps) => {
125
- const previewComponent = useMemo(() => {
126
- switch (templateId) {
127
- case 'todos-app':
128
- return (
129
- <TemplateShell
130
- title="Starter tasks"
131
- description="Track work items with filters, priorities, and per-tenant data isolation."
132
- showSaveAction={false}
133
- >
134
- <TodosTaskList />
135
- </TemplateShell>
136
- );
137
- case 'messaging-app':
138
- return (
139
- <TemplateShell
140
- title="Messaging workspace"
141
- description="Realtime-ready messaging surface with optimistic delivery."
142
- showSaveAction={false}
143
- >
144
- <MessagingWorkspace />
145
- </TemplateShell>
146
- );
147
- case 'recipe-app-i18n':
148
- return (
149
- <TemplateShell
150
- title="Ceremony recipes"
151
- description="Switch locales and preview how rituals translate across teams."
152
- showSaveAction={false}
153
- >
154
- <RecipesExperience />
155
- </TemplateShell>
156
- );
157
- case 'saas-boilerplate':
158
- return (
159
- <TemplateShell
160
- title="SaaS Boilerplate"
161
- description="Multi-tenant organizations, projects, settings, and billing usage tracking."
162
- showSaveAction={false}
163
- >
164
- <SaasDashboard />
165
- </TemplateShell>
166
- );
167
- case 'crm-pipeline':
168
- return (
169
- <TemplateShell
170
- title="CRM Pipeline"
171
- description="Sales CRM with contacts, companies, deals, and pipeline stages."
172
- showSaveAction={false}
173
- >
174
- <CrmDashboard />
175
- </TemplateShell>
176
- );
177
- case 'agent-console':
178
- return (
179
- <TemplateShell
180
- title="AI Agent Console"
181
- description="AI agent orchestration with tools, agents, runs, and execution logs."
182
- showSaveAction={false}
183
- >
184
- <AgentDashboard />
185
- </TemplateShell>
186
- );
187
- case 'workflow-system':
188
- return (
189
- <TemplateShell
190
- title="Workflow System"
191
- description="Multi-step workflows with role-based approvals."
192
- showSaveAction={false}
193
- >
194
- <WorkflowDashboard />
195
- </TemplateShell>
196
- );
197
- case 'marketplace':
198
- return (
199
- <TemplateShell
200
- title="Marketplace"
201
- description="Two-sided marketplace with stores, products, and orders."
202
- showSaveAction={false}
203
- >
204
- <MarketplaceDashboard />
205
- </TemplateShell>
206
- );
207
- case 'integration-hub':
208
- return (
209
- <TemplateShell
210
- title="Integration Hub"
211
- description="Third-party integrations with sync and field mapping."
212
- showSaveAction={false}
213
- >
214
- <IntegrationDashboard />
215
- </TemplateShell>
216
- );
217
- case 'analytics-dashboard':
218
- return (
219
- <TemplateShell
220
- title="Analytics Dashboard"
221
- description="Custom dashboards with widgets and queries."
222
- showSaveAction={false}
223
- >
224
- <AnalyticsDashboard />
225
- </TemplateShell>
226
- );
227
- case null:
228
- return null;
229
- default:
230
- return null;
231
- }
232
- }, [templateId]);
124
+ const previewComponent = useMemo(() => {
125
+ switch (templateId) {
126
+ case 'todos-app':
127
+ return (
128
+ <TemplateShell
129
+ title="Starter tasks"
130
+ description="Track work items with filters, priorities, and per-tenant data isolation."
131
+ showSaveAction={false}
132
+ >
133
+ <TodosTaskList />
134
+ </TemplateShell>
135
+ );
136
+ case 'messaging-app':
137
+ return (
138
+ <TemplateShell
139
+ title="Messaging workspace"
140
+ description="Realtime-ready messaging surface with optimistic delivery."
141
+ showSaveAction={false}
142
+ >
143
+ <MessagingWorkspace />
144
+ </TemplateShell>
145
+ );
146
+ case 'recipe-app-i18n':
147
+ return (
148
+ <TemplateShell
149
+ title="Ceremony recipes"
150
+ description="Switch locales and preview how rituals translate across teams."
151
+ showSaveAction={false}
152
+ >
153
+ <RecipesExperience />
154
+ </TemplateShell>
155
+ );
156
+ case 'saas-boilerplate':
157
+ return (
158
+ <TemplateShell
159
+ title="SaaS Boilerplate"
160
+ description="Multi-tenant organizations, projects, settings, and billing usage tracking."
161
+ showSaveAction={false}
162
+ >
163
+ <SaasDashboard />
164
+ </TemplateShell>
165
+ );
166
+ case 'crm-pipeline':
167
+ return (
168
+ <TemplateShell
169
+ title="CRM Pipeline"
170
+ description="Sales CRM with contacts, companies, deals, and pipeline stages."
171
+ showSaveAction={false}
172
+ >
173
+ <CrmDashboard />
174
+ </TemplateShell>
175
+ );
176
+ case 'agent-console':
177
+ return (
178
+ <TemplateShell
179
+ title="AI Agent Console"
180
+ description="AI agent orchestration with tools, agents, runs, and execution logs."
181
+ showSaveAction={false}
182
+ >
183
+ <AgentDashboard />
184
+ </TemplateShell>
185
+ );
186
+ case 'workflow-system':
187
+ return (
188
+ <TemplateShell
189
+ title="Workflow System"
190
+ description="Multi-step workflows with role-based approvals."
191
+ showSaveAction={false}
192
+ >
193
+ <WorkflowDashboard />
194
+ </TemplateShell>
195
+ );
196
+ case 'marketplace':
197
+ return (
198
+ <TemplateShell
199
+ title="Marketplace"
200
+ description="Two-sided marketplace with stores, products, and orders."
201
+ showSaveAction={false}
202
+ >
203
+ <MarketplaceDashboard />
204
+ </TemplateShell>
205
+ );
206
+ case 'integration-hub':
207
+ return (
208
+ <TemplateShell
209
+ title="Integration Hub"
210
+ description="Third-party integrations with sync and field mapping."
211
+ showSaveAction={false}
212
+ >
213
+ <IntegrationDashboard />
214
+ </TemplateShell>
215
+ );
216
+ case 'analytics-dashboard':
217
+ return (
218
+ <TemplateShell
219
+ title="Analytics Dashboard"
220
+ description="Custom dashboards with widgets and queries."
221
+ showSaveAction={false}
222
+ >
223
+ <AnalyticsDashboard />
224
+ </TemplateShell>
225
+ );
226
+ case null:
227
+ return null;
228
+ default:
229
+ return null;
230
+ }
231
+ }, [templateId]);
233
232
 
234
- return (
235
- <Dialog open={!!previewComponent} onOpenChange={onClose}>
236
- {/*<DialogTrigger asChild>*/}
237
- {/* <Button variant="outline">Fullscreen Dialog</Button>*/}
238
- {/*</DialogTrigger>*/}
239
- <DialogContent className="mb-8 flex h-[calc(100vh-2rem)] min-w-[calc(100vw-2rem)] flex-col justify-between gap-0 p-0">
240
- <ScrollArea className="flex flex-col justify-between overflow-hidden">
241
- {/*<DialogHeader className="contents space-y-0 text-left">*/}
242
- {/* <DialogTitle className="px-6 pt-6">Product Information</DialogTitle>*/}
243
- {/* <DialogDescription asChild>*/}
244
- {/* </DialogDescription>*/}
245
- {/*</DialogHeader>*/}
246
- {previewComponent}
247
- </ScrollArea>
248
- {/*<DialogFooter className="px-6 pb-6 sm:justify-end">*/}
249
- {/* <DialogClose asChild>*/}
250
- {/* <Button variant="outline">*/}
251
- {/* <ChevronLeftIcon />*/}
252
- {/* Back*/}
253
- {/* </Button>*/}
254
- {/* </DialogClose>*/}
255
- {/* <Button type="button">Read More</Button>*/}
256
- {/*</DialogFooter>*/}
257
- </DialogContent>
258
- </Dialog>
259
- );
233
+ return (
234
+ <Dialog open={!!previewComponent} onOpenChange={onClose}>
235
+ {/*<DialogTrigger asChild>*/}
236
+ {/* <Button variant="outline">Fullscreen Dialog</Button>*/}
237
+ {/*</DialogTrigger>*/}
238
+ <DialogContent className="mb-8 flex h-[calc(100vh-2rem)] min-w-[calc(100vw-2rem)] flex-col justify-between gap-0 p-0">
239
+ <ScrollArea className="flex flex-col justify-between overflow-hidden">
240
+ {/*<DialogHeader className="contents space-y-0 text-left">*/}
241
+ {/* <DialogTitle className="px-6 pt-6">Product Information</DialogTitle>*/}
242
+ {/* <DialogDescription asChild>*/}
243
+ {/* </DialogDescription>*/}
244
+ {/*</DialogHeader>*/}
245
+ {previewComponent}
246
+ </ScrollArea>
247
+ {/*<DialogFooter className="px-6 pb-6 sm:justify-end">*/}
248
+ {/* <DialogClose asChild>*/}
249
+ {/* <Button variant="outline">*/}
250
+ {/* <ChevronLeftIcon />*/}
251
+ {/* Back*/}
252
+ {/* </Button>*/}
253
+ {/* </DialogClose>*/}
254
+ {/* <Button type="button">Read More</Button>*/}
255
+ {/*</DialogFooter>*/}
256
+ </DialogContent>
257
+ </Dialog>
258
+ );
260
259
  };
package/src/index.ts CHANGED
@@ -4,10 +4,10 @@ export * from './components/templates';
4
4
  export { submitContactForm } from './libs/email/contact';
5
5
  export { subscribeToNewsletter } from './libs/email/newsletter';
6
6
  export type {
7
- SubmitContactFormResult,
8
- SubmitNewsletterResult,
9
- SubmitWaitlistApplicationResult,
10
- SubmitWaitlistResult,
7
+ SubmitContactFormResult,
8
+ SubmitNewsletterResult,
9
+ SubmitWaitlistApplicationResult,
10
+ SubmitWaitlistResult,
11
11
  } from './libs/email/types';
12
12
  export { joinWaitlist } from './libs/email/waitlist';
13
13
  export { submitWaitlistApplication } from './libs/email/waitlist-application';
@@ -5,103 +5,103 @@ import { beforeEach, describe, expect, it } from 'bun:test';
5
5
  import { __internal, getEmailConfig, sendEmail } from './client';
6
6
 
7
7
  const ENV_KEYS = [
8
- 'SCALEWAY_ACCESS_KEY',
9
- 'SCALEWAY_SECRET_KEY',
10
- 'SCALEWAY_PROJECT_ID',
11
- 'SCALEWAY_ACCESS_KEY_QUEUE',
12
- 'SCALEWAY_SECRET_KEY_QUEUE',
13
- 'SCALEWAY_REGION',
14
- 'SCALEWAY_EMAIL_FROM_EMAIL',
15
- 'SCALEWAY_EMAIL_FROM_NAME',
16
- 'SCALEWAY_EMAIL_TEAM_EMAIL',
17
- 'SCALEWAY_EMAIL_TEAM_NAME',
8
+ 'SCALEWAY_ACCESS_KEY',
9
+ 'SCALEWAY_SECRET_KEY',
10
+ 'SCALEWAY_PROJECT_ID',
11
+ 'SCALEWAY_ACCESS_KEY_QUEUE',
12
+ 'SCALEWAY_SECRET_KEY_QUEUE',
13
+ 'SCALEWAY_REGION',
14
+ 'SCALEWAY_EMAIL_FROM_EMAIL',
15
+ 'SCALEWAY_EMAIL_FROM_NAME',
16
+ 'SCALEWAY_EMAIL_TEAM_EMAIL',
17
+ 'SCALEWAY_EMAIL_TEAM_NAME',
18
18
  ];
19
19
 
20
20
  const clearEnv = () => {
21
- ENV_KEYS.forEach((key) => {
22
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- Pragmatic use for environment cleanup in tests
23
- delete process.env[key];
24
- });
21
+ ENV_KEYS.forEach((key) => {
22
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- Pragmatic use for environment cleanup in tests
23
+ delete process.env[key];
24
+ });
25
25
  };
26
26
 
27
27
  const setEnv = (values: Partial<Record<string, string>>) => {
28
- Object.entries(values).forEach(([key, value]) => {
29
- process.env[key] = value;
30
- });
28
+ Object.entries(values).forEach(([key, value]) => {
29
+ process.env[key] = value;
30
+ });
31
31
  };
32
32
 
33
33
  describe('email client config', () => {
34
- beforeEach(() => {
35
- __internal.resetCaches();
36
- clearEnv();
37
- });
34
+ beforeEach(() => {
35
+ __internal.resetCaches();
36
+ clearEnv();
37
+ });
38
38
 
39
- it('returns a failure result when credentials are missing', () => {
40
- const result = getEmailConfig();
41
- expect(result.ok).toBeFalse();
42
- expect(result.config).toBeUndefined();
43
- });
39
+ it('returns a failure result when credentials are missing', () => {
40
+ const result = getEmailConfig();
41
+ expect(result.ok).toBeFalse();
42
+ expect(result.config).toBeUndefined();
43
+ });
44
44
 
45
- it('prefers Scaleway env variables for config and region mapping', () => {
46
- setEnv({
47
- SCALEWAY_ACCESS_KEY: 'access',
48
- SCALEWAY_SECRET_KEY: 'secret',
49
- SCALEWAY_PROJECT_ID: 'project-123',
50
- SCALEWAY_EMAIL_FROM_EMAIL: 'from@example.com',
51
- SCALEWAY_EMAIL_FROM_NAME: 'From Name',
52
- SCALEWAY_EMAIL_TEAM_EMAIL: 'team@example.com',
53
- SCALEWAY_EMAIL_TEAM_NAME: 'Team Name',
54
- });
45
+ it('prefers Scaleway env variables for config and region mapping', () => {
46
+ setEnv({
47
+ SCALEWAY_ACCESS_KEY: 'access',
48
+ SCALEWAY_SECRET_KEY: 'secret',
49
+ SCALEWAY_PROJECT_ID: 'project-123',
50
+ SCALEWAY_EMAIL_FROM_EMAIL: 'from@example.com',
51
+ SCALEWAY_EMAIL_FROM_NAME: 'From Name',
52
+ SCALEWAY_EMAIL_TEAM_EMAIL: 'team@example.com',
53
+ SCALEWAY_EMAIL_TEAM_NAME: 'Team Name',
54
+ });
55
55
 
56
- const result = getEmailConfig();
57
- expect(result.ok).toBeTrue();
58
- expect(result.config?.accessKey).toBe('access');
59
- expect(result.config?.secretKey).toBe('secret');
60
- expect(result.config?.projectId).toBe('project-123');
61
- expect(result.config?.region).toBe('fr-par');
62
- expect(result.config?.from.email).toBe('from@example.com');
63
- expect(result.config?.from.name).toBe('From Name');
64
- expect(result.config?.teamInbox.email).toBe('team@example.com');
65
- expect(result.config?.teamInbox.name).toBe('Team Name');
66
- });
56
+ const result = getEmailConfig();
57
+ expect(result.ok).toBeTrue();
58
+ expect(result.config?.accessKey).toBe('access');
59
+ expect(result.config?.secretKey).toBe('secret');
60
+ expect(result.config?.projectId).toBe('project-123');
61
+ expect(result.config?.region).toBe('fr-par');
62
+ expect(result.config?.from.email).toBe('from@example.com');
63
+ expect(result.config?.from.name).toBe('From Name');
64
+ expect(result.config?.teamInbox.email).toBe('team@example.com');
65
+ expect(result.config?.teamInbox.name).toBe('Team Name');
66
+ });
67
67
 
68
- it('uses provided API factory to send email with reply-to header', async () => {
69
- setEnv({
70
- SCALEWAY_ACCESS_KEY: 'access',
71
- SCALEWAY_SECRET_KEY: 'secret',
72
- SCALEWAY_PROJECT_ID: 'project-123',
73
- });
68
+ it('uses provided API factory to send email with reply-to header', async () => {
69
+ setEnv({
70
+ SCALEWAY_ACCESS_KEY: 'access',
71
+ SCALEWAY_SECRET_KEY: 'secret',
72
+ SCALEWAY_PROJECT_ID: 'project-123',
73
+ });
74
74
 
75
- let captured: unknown = null;
75
+ let captured: unknown = null;
76
76
 
77
- __internal.setClient({
78
- async createEmail(request: unknown) {
79
- captured = request;
80
- return { emails: [] };
81
- },
82
- });
77
+ __internal.setClient({
78
+ async createEmail(request: unknown) {
79
+ captured = request;
80
+ return { emails: [] };
81
+ },
82
+ });
83
83
 
84
- const config = getEmailConfig().config!;
84
+ const config = getEmailConfig().config!;
85
85
 
86
- const response = await sendEmail(config, {
87
- to: [{ email: 'user@example.com' }],
88
- subject: 'Subject',
89
- text: 'Plain text',
90
- html: '<p>html</p>',
91
- replyTo: 'reply@example.com',
92
- context: 'test',
93
- });
86
+ const response = await sendEmail(config, {
87
+ to: [{ email: 'user@example.com' }],
88
+ subject: 'Subject',
89
+ text: 'Plain text',
90
+ html: '<p>html</p>',
91
+ replyTo: 'reply@example.com',
92
+ context: 'test',
93
+ });
94
94
 
95
- expect(response.success).toBeTrue();
96
- const createEmailRequest = captured as Record<string, unknown>;
97
- expect(createEmailRequest.region).toBe(config.region);
98
- expect(createEmailRequest.projectId).toBe(config.projectId);
99
- expect(createEmailRequest.from).toStrictEqual(config.from);
100
- expect(createEmailRequest.to).toStrictEqual([
101
- { email: 'user@example.com' },
102
- ]);
103
- expect(createEmailRequest.additionalHeaders).toStrictEqual([
104
- { key: 'Reply-To', value: 'reply@example.com' },
105
- ]);
106
- });
95
+ expect(response.success).toBeTrue();
96
+ const createEmailRequest = captured as Record<string, unknown>;
97
+ expect(createEmailRequest.region).toBe(config.region);
98
+ expect(createEmailRequest.projectId).toBe(config.projectId);
99
+ expect(createEmailRequest.from).toStrictEqual(config.from);
100
+ expect(createEmailRequest.to).toStrictEqual([
101
+ { email: 'user@example.com' },
102
+ ]);
103
+ expect(createEmailRequest.additionalHeaders).toStrictEqual([
104
+ { key: 'Reply-To', value: 'reply@example.com' },
105
+ ]);
106
+ });
107
107
  });