@contractspec/bundle.marketing 3.7.5 → 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 (164) hide show
  1. package/.turbo/turbo-build.log +84 -84
  2. package/AGENTS.md +29 -21
  3. package/CHANGELOG.md +27 -0
  4. package/README.md +36 -49
  5. package/dist/browser/components/marketing/ChangelogPage.js +8 -8
  6. package/dist/browser/components/marketing/CofounderPage.js +167 -523
  7. package/dist/browser/components/marketing/ContactClient.js +200 -207
  8. package/dist/browser/components/marketing/ContributePage.js +211 -463
  9. package/dist/browser/components/marketing/DesignPartnerPage.js +165 -218
  10. package/dist/browser/components/marketing/LandingPage.js +464 -568
  11. package/dist/browser/components/marketing/PricingClient.js +213 -839
  12. package/dist/browser/components/marketing/ProductClientPage.js +265 -463
  13. package/dist/browser/components/marketing/index.js +2007 -3338
  14. package/dist/browser/components/marketing/pricing-thinking-modal.js +12 -12
  15. package/dist/browser/components/marketing/sections/AudienceSection.js +2 -2
  16. package/dist/browser/components/marketing/sections/CorePositioningSection.js +2 -2
  17. package/dist/browser/components/marketing/sections/CtaSection.js +3 -3
  18. package/dist/browser/components/marketing/sections/FearsSection.js +3 -3
  19. package/dist/browser/components/marketing/sections/HeroMarketingSection.js +6 -6
  20. package/dist/browser/components/marketing/sections/IconGridSection.js +2 -2
  21. package/dist/browser/components/marketing/sections/OutputsSection.js +2 -2
  22. package/dist/browser/components/marketing/sections/ProblemSection.js +2 -2
  23. package/dist/browser/components/marketing/sections/SolutionSection.js +2 -2
  24. package/dist/browser/components/marketing/sections/StepsSection.js +4 -4
  25. package/dist/browser/components/marketing/studio-signup-section.js +25 -41
  26. package/dist/browser/components/templates/TemplatesClientPage.js +2324 -3578
  27. package/dist/browser/components/templates/TemplatesPage.js +1 -1
  28. package/dist/browser/components/templates/TemplatesPreviewModal.js +3 -3
  29. package/dist/browser/components/templates/index.js +2361 -3615
  30. package/dist/browser/index.js +2363 -3617
  31. package/dist/browser/libs/email/client.js +1 -1
  32. package/dist/browser/libs/email/contact.js +1 -1
  33. package/dist/browser/libs/email/newsletter.js +1 -1
  34. package/dist/browser/libs/email/waitlist-application.js +1 -1
  35. package/dist/browser/libs/email/waitlist.js +1 -1
  36. package/dist/browser/registry/engine.js +2003 -3334
  37. package/dist/browser/registry/index.js +2003 -3334
  38. package/dist/browser/registry/registry-docs.js +2 -2
  39. package/dist/browser/registry/registry-landing.js +2007 -3338
  40. package/dist/browser/registry/registry.js +2003 -3334
  41. package/dist/browser/registry/utils.js +2003 -3334
  42. package/dist/components/marketing/ChangelogPage.js +8 -8
  43. package/dist/components/marketing/CofounderPage.js +167 -523
  44. package/dist/components/marketing/ContactClient.js +200 -207
  45. package/dist/components/marketing/ContributePage.d.ts +0 -2
  46. package/dist/components/marketing/ContributePage.js +211 -463
  47. package/dist/components/marketing/DesignPartnerPage.js +165 -218
  48. package/dist/components/marketing/LandingPage.js +464 -568
  49. package/dist/components/marketing/PricingClient.js +213 -839
  50. package/dist/components/marketing/ProductClientPage.js +265 -463
  51. package/dist/components/marketing/index.d.ts +5 -5
  52. package/dist/components/marketing/index.js +2007 -3338
  53. package/dist/components/marketing/pricing-thinking-modal.js +12 -12
  54. package/dist/components/marketing/sections/AudienceSection.js +2 -2
  55. package/dist/components/marketing/sections/CorePositioningSection.js +2 -2
  56. package/dist/components/marketing/sections/CtaSection.js +3 -3
  57. package/dist/components/marketing/sections/FearsSection.js +3 -3
  58. package/dist/components/marketing/sections/HeroMarketingSection.js +6 -6
  59. package/dist/components/marketing/sections/IconGridSection.d.ts +3 -3
  60. package/dist/components/marketing/sections/IconGridSection.js +2 -2
  61. package/dist/components/marketing/sections/OutputsSection.js +2 -2
  62. package/dist/components/marketing/sections/ProblemSection.js +2 -2
  63. package/dist/components/marketing/sections/SolutionSection.js +2 -2
  64. package/dist/components/marketing/sections/StepsSection.js +4 -4
  65. package/dist/components/marketing/studio-signup-section.js +25 -41
  66. package/dist/components/templates/TemplatesClientPage.js +2324 -3578
  67. package/dist/components/templates/TemplatesPage.js +1 -1
  68. package/dist/components/templates/TemplatesPreviewModal.js +3 -3
  69. package/dist/components/templates/index.js +2361 -3615
  70. package/dist/index.js +2363 -3617
  71. package/dist/libs/email/client.js +1 -1
  72. package/dist/libs/email/contact.js +1 -1
  73. package/dist/libs/email/newsletter.js +1 -1
  74. package/dist/libs/email/waitlist-application.js +1 -1
  75. package/dist/libs/email/waitlist.js +1 -1
  76. package/dist/node/components/marketing/ChangelogPage.js +8 -8
  77. package/dist/node/components/marketing/CofounderPage.js +167 -523
  78. package/dist/node/components/marketing/ContactClient.js +200 -207
  79. package/dist/node/components/marketing/ContributePage.js +211 -463
  80. package/dist/node/components/marketing/DesignPartnerPage.js +165 -218
  81. package/dist/node/components/marketing/LandingPage.js +464 -568
  82. package/dist/node/components/marketing/PricingClient.js +213 -839
  83. package/dist/node/components/marketing/ProductClientPage.js +265 -463
  84. package/dist/node/components/marketing/index.js +2007 -3338
  85. package/dist/node/components/marketing/pricing-thinking-modal.js +12 -12
  86. package/dist/node/components/marketing/sections/AudienceSection.js +2 -2
  87. package/dist/node/components/marketing/sections/CorePositioningSection.js +2 -2
  88. package/dist/node/components/marketing/sections/CtaSection.js +3 -3
  89. package/dist/node/components/marketing/sections/FearsSection.js +3 -3
  90. package/dist/node/components/marketing/sections/HeroMarketingSection.js +6 -6
  91. package/dist/node/components/marketing/sections/IconGridSection.js +2 -2
  92. package/dist/node/components/marketing/sections/OutputsSection.js +2 -2
  93. package/dist/node/components/marketing/sections/ProblemSection.js +2 -2
  94. package/dist/node/components/marketing/sections/SolutionSection.js +2 -2
  95. package/dist/node/components/marketing/sections/StepsSection.js +4 -4
  96. package/dist/node/components/marketing/studio-signup-section.js +25 -41
  97. package/dist/node/components/templates/TemplatesClientPage.js +2324 -3578
  98. package/dist/node/components/templates/TemplatesPage.js +1 -1
  99. package/dist/node/components/templates/TemplatesPreviewModal.js +3 -3
  100. package/dist/node/components/templates/index.js +2361 -3615
  101. package/dist/node/index.js +2363 -3617
  102. package/dist/node/libs/email/client.js +1 -1
  103. package/dist/node/libs/email/contact.js +1 -1
  104. package/dist/node/libs/email/newsletter.js +1 -1
  105. package/dist/node/libs/email/waitlist-application.js +1 -1
  106. package/dist/node/libs/email/waitlist.js +1 -1
  107. package/dist/node/registry/engine.js +2003 -3334
  108. package/dist/node/registry/index.js +2003 -3334
  109. package/dist/node/registry/registry-docs.js +2 -2
  110. package/dist/node/registry/registry-landing.js +2007 -3338
  111. package/dist/node/registry/registry.js +2003 -3334
  112. package/dist/node/registry/utils.js +2003 -3334
  113. package/dist/registry/engine.js +2003 -3334
  114. package/dist/registry/index.js +2003 -3334
  115. package/dist/registry/registry-docs.js +2 -2
  116. package/dist/registry/registry-landing.js +2007 -3338
  117. package/dist/registry/registry.js +2003 -3334
  118. package/dist/registry/utils.js +2003 -3334
  119. package/package.json +29 -29
  120. package/src/bundles/MarketingBundle.ts +273 -273
  121. package/src/components/marketing/ChangelogPage.tsx +72 -100
  122. package/src/components/marketing/CofounderPage.tsx +120 -384
  123. package/src/components/marketing/ContactClient.tsx +164 -154
  124. package/src/components/marketing/ContributePage.tsx +139 -313
  125. package/src/components/marketing/DesignPartnerPage.tsx +133 -171
  126. package/src/components/marketing/LandingPage.tsx +353 -25
  127. package/src/components/marketing/PricingClient.tsx +192 -437
  128. package/src/components/marketing/ProductClientPage.tsx +255 -377
  129. package/src/components/marketing/index.ts +5 -5
  130. package/src/components/marketing/pricing-thinking-modal.tsx +197 -197
  131. package/src/components/marketing/sections/AudienceSection.tsx +55 -56
  132. package/src/components/marketing/sections/CorePositioningSection.tsx +37 -37
  133. package/src/components/marketing/sections/CtaSection.tsx +49 -50
  134. package/src/components/marketing/sections/DevelopersSection.tsx +26 -27
  135. package/src/components/marketing/sections/FearsSection.tsx +36 -37
  136. package/src/components/marketing/sections/HeroMarketingSection.tsx +59 -59
  137. package/src/components/marketing/sections/IconGridSection.tsx +71 -71
  138. package/src/components/marketing/sections/OutputsSection.tsx +51 -52
  139. package/src/components/marketing/sections/ProblemSection.tsx +39 -40
  140. package/src/components/marketing/sections/SolutionSection.tsx +39 -40
  141. package/src/components/marketing/sections/StepsSection.tsx +47 -48
  142. package/src/components/marketing/studio-signup-section.tsx +39 -41
  143. package/src/components/templates/TemplatesClientPage.tsx +727 -685
  144. package/src/components/templates/TemplatesPage.tsx +110 -110
  145. package/src/components/templates/TemplatesPreviewModal.tsx +197 -198
  146. package/src/index.ts +4 -4
  147. package/src/libs/email/client.test.ts +81 -81
  148. package/src/libs/email/client.ts +111 -111
  149. package/src/libs/email/contact.ts +35 -35
  150. package/src/libs/email/newsletter.ts +46 -46
  151. package/src/libs/email/types.ts +29 -29
  152. package/src/libs/email/utils.ts +5 -5
  153. package/src/libs/email/waitlist-application.ts +72 -72
  154. package/src/libs/email/waitlist.ts +46 -46
  155. package/src/libs/pricing-examples.ts +12 -12
  156. package/src/registry/engine.ts +16 -16
  157. package/src/registry/factory.ts +57 -57
  158. package/src/registry/registry-docs.ts +656 -666
  159. package/src/registry/registry-landing.ts +94 -95
  160. package/src/registry/registry.ts +36 -37
  161. package/src/registry/types.ts +2 -2
  162. package/src/registry/utils.ts +56 -56
  163. package/tsconfig.json +11 -11
  164. 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
  });