@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,714 +1,756 @@
1
1
  'use client';
2
2
 
3
- import { useState } from 'react';
4
- import { Search } from 'lucide-react';
5
- import { cn } from '@contractspec/lib.ui-kit-core/utils';
6
- import Link from 'next/link';
3
+ import {
4
+ analyticsEventNames,
5
+ captureAnalyticsEvent,
6
+ } from '@contractspec/bundle.library/libs/posthog/client';
7
7
  import type {
8
- RegistryTemplate,
9
- TemplateId,
8
+ RegistryTemplate,
9
+ TemplateId,
10
10
  } from '@contractspec/lib.example-shared-ui';
11
11
  import { useRegistryTemplates } from '@contractspec/lib.example-shared-ui';
12
- import { getTemplate } from '@contractspec/module.examples';
13
- import {
14
- Tooltip,
15
- TooltipContent,
16
- TooltipProvider,
17
- TooltipTrigger,
18
- } from '@contractspec/lib.ui-kit-web/ui/tooltip';
19
- import {
20
- analyticsEventNames,
21
- captureAnalyticsEvent,
22
- } from '@contractspec/bundle.library/libs/posthog/client';
12
+ import { cn } from '@contractspec/lib.ui-kit-core/utils';
23
13
  import {
24
- Dialog,
25
- DialogContent,
26
- DialogDescription,
27
- DialogHeader,
28
- DialogTitle,
14
+ Dialog,
15
+ DialogContent,
16
+ DialogDescription,
17
+ DialogHeader,
18
+ DialogTitle,
29
19
  } from '@contractspec/lib.ui-kit-web/ui/dialog';
20
+ import {
21
+ Tooltip,
22
+ TooltipContent,
23
+ TooltipProvider,
24
+ TooltipTrigger,
25
+ } from '@contractspec/lib.ui-kit-web/ui/tooltip';
26
+ import { getTemplate } from '@contractspec/module.examples';
27
+ import { Search } from 'lucide-react';
28
+ import Link from 'next/link';
29
+ import { useState } from 'react';
30
30
  import { StudioSignupSection } from '../marketing';
31
31
  import { TemplatePreviewModal } from './TemplatesPreviewModal';
32
32
 
33
33
  const templates = [
34
- {
35
- id: 'minimal-example',
36
- templateId: 'todos-app' as TemplateId,
37
- title: 'Minimal Example',
38
- description:
39
- 'A minimal template to get you running in minutes. Perfect for exploring the engine.',
40
- tags: ['Getting Started'],
41
- capabilities: 'Basic Forms, Auth',
42
- isStarter: true,
43
- previewUrl: '/sandbox?template=minimal-example',
44
- docsUrl: '/docs/getting-started/hello-world',
45
- },
46
- // ============================================
47
- // Phase 1 Examples (using cross-cutting modules)
48
- // ============================================
49
- {
50
- id: 'saas-boilerplate',
51
- templateId: 'saas-boilerplate' as TemplateId,
52
- title: 'SaaS Boilerplate',
53
- description:
54
- 'Complete SaaS foundation with multi-tenant orgs, projects, settings, and billing usage.',
55
- tags: ['Getting Started', 'SaaS', 'Business'],
56
- capabilities: 'Multi-tenancy, RBAC, Projects, Billing',
57
- isNew: true,
58
- previewUrl: '/sandbox?template=saas-boilerplate',
59
- docsUrl: '/docs/templates/saas-boilerplate',
60
- },
61
- {
62
- id: 'crm-pipeline',
63
- templateId: 'crm-pipeline' as TemplateId,
64
- title: 'CRM Pipeline',
65
- description:
66
- 'Sales CRM with contacts, companies, deals, pipeline stages, and task management.',
67
- tags: ['CRM', 'Business'],
68
- capabilities: 'Contacts, Deals, Pipelines, Tasks',
69
- isNew: true,
70
- previewUrl: '/sandbox?template=crm-pipeline',
71
- docsUrl: '/docs/templates/crm-pipeline',
72
- },
73
- {
74
- id: 'agent-console',
75
- templateId: 'agent-console' as TemplateId,
76
- title: 'AI Agent Console',
77
- description:
78
- 'AI agent orchestration platform with tools, agents, runs, and execution logs.',
79
- tags: ['AI', 'Ops'],
80
- capabilities: 'Tools, Agents, Runs, Metrics',
81
- isNew: true,
82
- previewUrl: '/sandbox?template=agent-console',
83
- docsUrl: '/docs/templates/agent-console',
84
- },
85
- // ============================================
86
- // Phase 2-4 Examples
87
- // ============================================
88
- {
89
- id: 'workflow-system',
90
- templateId: 'workflow-system' as TemplateId,
91
- title: 'Workflow / Approval System',
92
- description:
93
- 'Multi-step workflows with role-based approvals and state transitions.',
94
- tags: ['Business', 'Ops'],
95
- capabilities: 'Workflows, Approvals, State Machine',
96
- isNew: true,
97
- previewUrl: '/sandbox?template=workflow-system',
98
- docsUrl: '/docs/templates/workflow-system',
99
- },
100
- {
101
- id: 'marketplace',
102
- templateId: 'marketplace' as TemplateId,
103
- title: 'Marketplace',
104
- description:
105
- 'Two-sided marketplace with stores, products, orders, and payouts.',
106
- tags: ['Business', 'Payments'],
107
- capabilities: 'Stores, Products, Orders, Payouts',
108
- isNew: true,
109
- previewUrl: '/sandbox?template=marketplace',
110
- docsUrl: '/docs/templates/marketplace',
111
- },
112
- {
113
- id: 'integration-hub',
114
- templateId: 'integration-hub' as TemplateId,
115
- title: 'Integration Hub',
116
- description:
117
- 'Third-party integrations with connections, sync configs, and field mapping.',
118
- tags: ['Ops', 'AI'],
119
- capabilities: 'Integrations, Connections, Sync',
120
- isNew: true,
121
- previewUrl: '/sandbox?template=integration-hub',
122
- docsUrl: '/docs/templates/integration-hub',
123
- },
124
- // ============================================
125
- // Learning Journeys
126
- // ============================================
127
- {
128
- id: 'learning-journey-studio-onboarding',
129
- templateId: 'learning-journey-studio-onboarding' as TemplateId,
130
- title: 'Learning Journey — Studio Getting Started',
131
- description:
132
- 'First 30 minutes in Studio: choose template, edit spec, regenerate, playground, evolution.',
133
- tags: ['Learning', 'Onboarding'],
134
- capabilities: 'Spec-first onboarding, XP/streak, progress widget',
135
- isNew: true,
136
- previewUrl: '/sandbox?template=learning-journey-studio-onboarding',
137
- docsUrl: '/docs/templates/learning-journey-studio-onboarding',
138
- },
139
- {
140
- id: 'learning-journey-platform-tour',
141
- templateId: 'learning-journey-platform-tour' as TemplateId,
142
- title: 'Learning Journey — Platform Primitives Tour',
143
- description:
144
- 'Touch identity, audit, notifications, jobs, flags, files, metering once with guided steps.',
145
- tags: ['Learning', 'Platform'],
146
- capabilities: 'Cross-module tour with event-driven completion',
147
- isNew: true,
148
- previewUrl: '/sandbox?template=learning-journey-platform-tour',
149
- docsUrl: '/docs/templates/learning-journey-platform-tour',
150
- },
151
- {
152
- id: 'learning-journey-crm-onboarding',
153
- templateId: 'learning-journey-crm-onboarding' as TemplateId,
154
- title: 'Learning Journey — CRM First Win',
155
- description:
156
- 'Get to first closed-won deal: pipeline, contact/company, deal, stages, follow-up.',
157
- tags: ['Learning', 'CRM'],
158
- capabilities: 'CRM onboarding with XP/streak/badge',
159
- isNew: true,
160
- previewUrl: '/sandbox?template=learning-journey-crm-onboarding',
161
- docsUrl: '/docs/templates/learning-journey-crm-onboarding',
162
- },
163
- {
164
- id: 'analytics-dashboard',
165
- templateId: 'analytics-dashboard' as TemplateId,
166
- title: 'Analytics Dashboard',
167
- description:
168
- 'Custom dashboards with widgets, saved queries, and real-time visualization.',
169
- tags: ['Business', 'Ops'],
170
- capabilities: 'Dashboards, Widgets, Queries',
171
- isNew: true,
172
- previewUrl: '/sandbox?template=analytics-dashboard',
173
- docsUrl: '/docs/templates/analytics-dashboard',
174
- },
175
- // ============================================
176
- // Classic Templates
177
- // ============================================
178
- {
179
- id: 'plumber-ops',
180
- templateId: 'messaging-app' as TemplateId,
181
- title: 'Plumber Ops',
182
- description:
183
- 'Complete workflow: Quotes → Deposit → Job → Invoice → Payment. Policy-enforced approvals.',
184
- tags: ['Trades', 'Payments'],
185
- capabilities: 'Quotes, Jobs, Invoicing, Payments',
186
- previewUrl: '/sandbox?template=plumber-ops',
187
- docsUrl: '/docs/specs/workflows',
188
- },
189
- {
190
- id: 'coliving-management',
191
- templateId: 'recipe-app-i18n' as TemplateId,
192
- title: 'Coliving Management',
193
- description:
194
- 'Coliving management: Onboarding, chores, shared wallet. Multi-party approvals built-in.',
195
- tags: ['Coliving', 'Finance'],
196
- capabilities: 'Tasks, Approvals, Payments',
197
- previewUrl: '/sandbox?template=coliving-management',
198
- docsUrl: '/docs/specs/workflows',
199
- },
200
- {
201
- id: 'chores-allowance',
202
- templateId: 'todos-app' as TemplateId,
203
- title: 'Chores & Allowance',
204
- description:
205
- 'Family task management with approval workflows. Teach financial accountability safely.',
206
- tags: ['Family', 'Ops'],
207
- capabilities: 'Tasks, Approvals, Notifications',
208
- previewUrl: '/sandbox?template=chores-allowance',
209
- docsUrl: '/docs/specs/workflows',
210
- },
211
- {
212
- id: 'service-dispatch',
213
- templateId: 'messaging-app' as TemplateId,
214
- title: 'Service Dispatch',
215
- description:
216
- 'Field service scheduling, routing, and invoicing. Real-time coordination with policy gates.',
217
- tags: ['Ops', 'Trades'],
218
- capabilities: 'Scheduling, Maps, Invoicing',
219
- previewUrl: '/sandbox?template=service-dispatch',
220
- docsUrl: '/docs/specs/workflows',
221
- },
222
- {
223
- id: 'content-review',
224
- templateId: 'todos-app' as TemplateId,
225
- title: 'Content Review',
226
- description:
227
- 'Multi-stage approval workflow for content. Audit trail for every decision.',
228
- tags: ['Ops'],
229
- capabilities: 'Workflows, Approvals, Comments',
230
- previewUrl: '/sandbox?template=content-review',
231
- docsUrl: '/docs/specs/workflows',
232
- },
34
+ {
35
+ id: 'minimal-example',
36
+ templateId: 'todos-app' as TemplateId,
37
+ title: 'Minimal Example',
38
+ description:
39
+ 'A minimal template to get you running in minutes. Perfect for exploring the engine.',
40
+ tags: ['Getting Started'],
41
+ capabilities: 'Basic Forms, Auth',
42
+ isStarter: true,
43
+ previewUrl: '/sandbox?template=minimal-example',
44
+ docsUrl: '/docs/getting-started/hello-world',
45
+ },
46
+ // ============================================
47
+ // Phase 1 Examples (using cross-cutting modules)
48
+ // ============================================
49
+ {
50
+ id: 'saas-boilerplate',
51
+ templateId: 'saas-boilerplate' as TemplateId,
52
+ title: 'SaaS Boilerplate',
53
+ description:
54
+ 'Complete SaaS foundation with multi-tenant orgs, projects, settings, and billing usage.',
55
+ tags: ['Getting Started', 'SaaS', 'Business'],
56
+ capabilities: 'Multi-tenancy, RBAC, Projects, Billing',
57
+ isNew: true,
58
+ previewUrl: '/sandbox?template=saas-boilerplate',
59
+ docsUrl: '/docs/templates/saas-boilerplate',
60
+ },
61
+ {
62
+ id: 'crm-pipeline',
63
+ templateId: 'crm-pipeline' as TemplateId,
64
+ title: 'CRM Pipeline',
65
+ description:
66
+ 'Sales CRM with contacts, companies, deals, pipeline stages, and task management.',
67
+ tags: ['CRM', 'Business'],
68
+ capabilities: 'Contacts, Deals, Pipelines, Tasks',
69
+ isNew: true,
70
+ previewUrl: '/sandbox?template=crm-pipeline',
71
+ docsUrl: '/docs/templates/crm-pipeline',
72
+ },
73
+ {
74
+ id: 'agent-console',
75
+ templateId: 'agent-console' as TemplateId,
76
+ title: 'AI Agent Console',
77
+ description:
78
+ 'AI agent orchestration platform with tools, agents, runs, and execution logs.',
79
+ tags: ['AI', 'Ops'],
80
+ capabilities: 'Tools, Agents, Runs, Metrics',
81
+ isNew: true,
82
+ previewUrl: '/sandbox?template=agent-console',
83
+ docsUrl: '/docs/templates/agent-console',
84
+ },
85
+ // ============================================
86
+ // Phase 2-4 Examples
87
+ // ============================================
88
+ {
89
+ id: 'workflow-system',
90
+ templateId: 'workflow-system' as TemplateId,
91
+ title: 'Workflow / Approval System',
92
+ description:
93
+ 'Multi-step workflows with role-based approvals and state transitions.',
94
+ tags: ['Business', 'Ops'],
95
+ capabilities: 'Workflows, Approvals, State Machine',
96
+ isNew: true,
97
+ previewUrl: '/sandbox?template=workflow-system',
98
+ docsUrl: '/docs/templates/workflow-system',
99
+ },
100
+ {
101
+ id: 'marketplace',
102
+ templateId: 'marketplace' as TemplateId,
103
+ title: 'Marketplace',
104
+ description:
105
+ 'Two-sided marketplace with stores, products, orders, and payouts.',
106
+ tags: ['Business', 'Payments'],
107
+ capabilities: 'Stores, Products, Orders, Payouts',
108
+ isNew: true,
109
+ previewUrl: '/sandbox?template=marketplace',
110
+ docsUrl: '/docs/templates/marketplace',
111
+ },
112
+ {
113
+ id: 'integration-hub',
114
+ templateId: 'integration-hub' as TemplateId,
115
+ title: 'Integration Hub',
116
+ description:
117
+ 'Third-party integrations with connections, sync configs, and field mapping.',
118
+ tags: ['Ops', 'AI'],
119
+ capabilities: 'Integrations, Connections, Sync',
120
+ isNew: true,
121
+ previewUrl: '/sandbox?template=integration-hub',
122
+ docsUrl: '/docs/templates/integration-hub',
123
+ },
124
+ // ============================================
125
+ // Learning Journeys
126
+ // ============================================
127
+ {
128
+ id: 'learning-journey-studio-onboarding',
129
+ templateId: 'learning-journey-studio-onboarding' as TemplateId,
130
+ title: 'Learning Journey — Studio Getting Started',
131
+ description:
132
+ 'First 30 minutes in Studio: choose template, edit spec, regenerate, playground, evolution.',
133
+ tags: ['Learning', 'Onboarding'],
134
+ capabilities: 'Spec-first onboarding, XP/streak, progress widget',
135
+ isNew: true,
136
+ previewUrl: '/sandbox?template=learning-journey-studio-onboarding',
137
+ docsUrl: '/docs/templates/learning-journey-studio-onboarding',
138
+ },
139
+ {
140
+ id: 'learning-journey-platform-tour',
141
+ templateId: 'learning-journey-platform-tour' as TemplateId,
142
+ title: 'Learning Journey — Platform Primitives Tour',
143
+ description:
144
+ 'Touch identity, audit, notifications, jobs, flags, files, metering once with guided steps.',
145
+ tags: ['Learning', 'Platform'],
146
+ capabilities: 'Cross-module tour with event-driven completion',
147
+ isNew: true,
148
+ previewUrl: '/sandbox?template=learning-journey-platform-tour',
149
+ docsUrl: '/docs/templates/learning-journey-platform-tour',
150
+ },
151
+ {
152
+ id: 'learning-journey-crm-onboarding',
153
+ templateId: 'learning-journey-crm-onboarding' as TemplateId,
154
+ title: 'Learning Journey — CRM First Win',
155
+ description:
156
+ 'Get to first closed-won deal: pipeline, contact/company, deal, stages, follow-up.',
157
+ tags: ['Learning', 'CRM'],
158
+ capabilities: 'CRM onboarding with XP/streak/badge',
159
+ isNew: true,
160
+ previewUrl: '/sandbox?template=learning-journey-crm-onboarding',
161
+ docsUrl: '/docs/templates/learning-journey-crm-onboarding',
162
+ },
163
+ {
164
+ id: 'analytics-dashboard',
165
+ templateId: 'analytics-dashboard' as TemplateId,
166
+ title: 'Analytics Dashboard',
167
+ description:
168
+ 'Custom dashboards with widgets, saved queries, and real-time visualization.',
169
+ tags: ['Business', 'Ops'],
170
+ capabilities: 'Dashboards, Widgets, Queries',
171
+ isNew: true,
172
+ previewUrl: '/sandbox?template=analytics-dashboard',
173
+ docsUrl: '/docs/templates/analytics-dashboard',
174
+ },
175
+ // ============================================
176
+ // Classic Templates
177
+ // ============================================
178
+ {
179
+ id: 'plumber-ops',
180
+ templateId: 'messaging-app' as TemplateId,
181
+ title: 'Plumber Ops',
182
+ description:
183
+ 'Complete workflow: Quotes → Deposit → Job → Invoice → Payment. Policy-enforced approvals.',
184
+ tags: ['Trades', 'Payments'],
185
+ capabilities: 'Quotes, Jobs, Invoicing, Payments',
186
+ previewUrl: '/sandbox?template=plumber-ops',
187
+ docsUrl: '/docs/specs/workflows',
188
+ },
189
+ {
190
+ id: 'coliving-management',
191
+ templateId: 'recipe-app-i18n' as TemplateId,
192
+ title: 'Coliving Management',
193
+ description:
194
+ 'Coliving management: Onboarding, chores, shared wallet. Multi-party approvals built-in.',
195
+ tags: ['Coliving', 'Finance'],
196
+ capabilities: 'Tasks, Approvals, Payments',
197
+ previewUrl: '/sandbox?template=coliving-management',
198
+ docsUrl: '/docs/specs/workflows',
199
+ },
200
+ {
201
+ id: 'chores-allowance',
202
+ templateId: 'todos-app' as TemplateId,
203
+ title: 'Chores & Allowance',
204
+ description:
205
+ 'Family task management with approval workflows. Teach financial accountability safely.',
206
+ tags: ['Family', 'Ops'],
207
+ capabilities: 'Tasks, Approvals, Notifications',
208
+ previewUrl: '/sandbox?template=chores-allowance',
209
+ docsUrl: '/docs/specs/workflows',
210
+ },
211
+ {
212
+ id: 'service-dispatch',
213
+ templateId: 'messaging-app' as TemplateId,
214
+ title: 'Service Dispatch',
215
+ description:
216
+ 'Field service scheduling, routing, and invoicing. Real-time coordination with policy gates.',
217
+ tags: ['Ops', 'Trades'],
218
+ capabilities: 'Scheduling, Maps, Invoicing',
219
+ previewUrl: '/sandbox?template=service-dispatch',
220
+ docsUrl: '/docs/specs/workflows',
221
+ },
222
+ {
223
+ id: 'content-review',
224
+ templateId: 'todos-app' as TemplateId,
225
+ title: 'Content Review',
226
+ description:
227
+ 'Multi-stage approval workflow for content. Audit trail for every decision.',
228
+ tags: ['Ops'],
229
+ capabilities: 'Workflows, Approvals, Comments',
230
+ previewUrl: '/sandbox?template=content-review',
231
+ docsUrl: '/docs/specs/workflows',
232
+ },
233
233
  ];
234
234
  type LocalTemplate = (typeof templates)[number];
235
235
 
236
236
  const allTags = [
237
- 'Getting Started',
238
- 'SaaS',
239
- 'Business',
240
- 'CRM',
241
- 'AI',
242
- 'Trades',
243
- 'Coliving',
244
- 'Family',
245
- 'Ops',
246
- 'Payments',
247
- 'Learning',
248
- 'Platform',
237
+ 'Getting Started',
238
+ 'SaaS',
239
+ 'Business',
240
+ 'CRM',
241
+ 'AI',
242
+ 'Trades',
243
+ 'Coliving',
244
+ 'Family',
245
+ 'Ops',
246
+ 'Payments',
247
+ 'Learning',
248
+ 'Platform',
249
249
  ];
250
250
 
251
251
  export const TemplatesPage = () => {
252
- const [selectedTag, setSelectedTag] = useState<string | null>(null);
253
- const [search, setSearch] = useState('');
254
- const [preview, setPreview] = useState<TemplateId | null>(null);
255
- const [studioSignupModalOpen, setStudioSignupModalOpen] = useState(false);
256
- const [source, setSource] = useState<'local' | 'registry'>('local');
257
- const [selectedTemplateForCommand, setSelectedTemplateForCommand] = useState<
258
- RegistryTemplate | LocalTemplate | null
259
- >(null);
252
+ const [selectedTag, setSelectedTag] = useState<string | null>(null);
253
+ const [search, setSearch] = useState('');
254
+ const [preview, setPreview] = useState<TemplateId | null>(null);
255
+ const [studioSignupModalOpen, setStudioSignupModalOpen] = useState(false);
256
+ const [source, setSource] = useState<'local' | 'registry'>('local');
257
+ const [selectedTemplateForCommand, setSelectedTemplateForCommand] = useState<
258
+ RegistryTemplate | LocalTemplate | null
259
+ >(null);
260
260
 
261
- const { data: registryTemplates = [], isLoading: registryLoading } =
262
- useRegistryTemplates();
261
+ const { data: registryTemplates = [], isLoading: registryLoading } =
262
+ useRegistryTemplates();
263
263
 
264
- const filtered = templates.filter((t) => {
265
- const matchTag = !selectedTag || t.tags.includes(selectedTag);
266
- const matchSearch =
267
- !search ||
268
- t.title.toLowerCase().includes(search.toLowerCase()) ||
269
- t.description.toLowerCase().includes(search.toLowerCase());
270
- return matchTag && matchSearch;
271
- });
264
+ const filtered = templates.filter((t) => {
265
+ const matchTag = !selectedTag || t.tags.includes(selectedTag);
266
+ const matchSearch =
267
+ !search ||
268
+ t.title.toLowerCase().includes(search.toLowerCase()) ||
269
+ t.description.toLowerCase().includes(search.toLowerCase());
270
+ return matchTag && matchSearch;
271
+ });
272
272
 
273
- const commandId = selectedTemplateForCommand
274
- ? 'templateId' in selectedTemplateForCommand
275
- ? selectedTemplateForCommand.templateId
276
- : selectedTemplateForCommand.id
277
- : '';
273
+ const commandId = selectedTemplateForCommand
274
+ ? 'templateId' in selectedTemplateForCommand
275
+ ? selectedTemplateForCommand.templateId
276
+ : selectedTemplateForCommand.id
277
+ : '';
278
278
 
279
- return (
280
- <TooltipProvider>
281
- <main className="">
282
- {/* Hero */}
283
- <section className="section-padding hero-gradient border-border relative border-b">
284
- <div className="mx-auto max-w-4xl space-y-6 text-center">
285
- <h1 className="text-5xl leading-tight font-bold md:text-6xl">
286
- Recipe templates
287
- </h1>
288
- <p className="text-muted-foreground text-lg">
289
- Ready-to-use, customizable recipes. Policies built in. One-click
290
- deploy.
291
- </p>
292
- </div>
293
- </section>
279
+ return (
280
+ <TooltipProvider>
281
+ <main>
282
+ <section className="section-padding hero-gradient border-border/70 border-b">
283
+ <div className="editorial-shell space-y-8">
284
+ <div className="max-w-4xl space-y-5">
285
+ <p className="editorial-kicker">Proof through real scenarios</p>
286
+ <h1 className="editorial-title">
287
+ Templates that show the open system in practice.
288
+ </h1>
289
+ <p className="editorial-subtitle">
290
+ These scenarios are the fastest way to understand ContractSpec:
291
+ explicit contracts, aligned surfaces, and an adoption path from
292
+ OSS exploration into Studio deployment.
293
+ </p>
294
+ </div>
295
+ <div className="editorial-proof-strip">
296
+ <div className="editorial-stat">
297
+ <span className="editorial-stat-value">{templates.length}</span>
298
+ <span className="editorial-label">curated scenarios</span>
299
+ </div>
300
+ <div className="editorial-stat">
301
+ <span className="editorial-stat-value">2</span>
302
+ <span className="editorial-label">entry paths</span>
303
+ </div>
304
+ <div className="editorial-stat">
305
+ <span className="editorial-stat-value">OSS</span>
306
+ <span className="editorial-label">first, Studio second</span>
307
+ </div>
308
+ </div>
309
+ </div>
310
+ </section>
294
311
 
295
- {/* Search & Filter */}
296
- <section className="section-padding border-border border-b">
297
- <div className="mx-auto max-w-6xl space-y-6">
298
- <div className="flex items-center justify-between gap-3">
299
- <div className="text-muted-foreground text-sm">Source:</div>
300
- <div className="flex gap-2">
301
- <button
302
- onClick={() => setSource('local')}
303
- className={cn(
304
- 'rounded-full px-4 py-2 text-sm font-medium transition-colors',
305
- {
306
- 'bg-violet-500 text-white': source === 'local',
307
- 'bg-card border-border hover:bg-card/80 border':
308
- source !== 'local',
309
- }
310
- )}
311
- aria-pressed={source === 'local'}
312
- >
313
- Local
314
- </button>
315
- <button
316
- onClick={() => setSource('registry')}
317
- className={cn(
318
- 'rounded-full px-4 py-2 text-sm font-medium transition-colors',
319
- {
320
- 'bg-violet-500 text-white': source === 'registry',
321
- 'bg-card border-border hover:bg-card/80 border':
322
- source !== 'registry',
323
- }
324
- )}
325
- aria-pressed={source === 'registry'}
326
- >
327
- Community
328
- </button>
329
- </div>
330
- </div>
331
- <div className="relative">
332
- <Search
333
- className="text-muted-foreground absolute top-3 left-3"
334
- size={20}
335
- />
336
- <input
337
- type="text"
338
- placeholder="Search templates..."
339
- value={search}
340
- onChange={(e) => setSearch(e.target.value)}
341
- className="bg-card border-border w-full rounded-lg border py-3 pr-4 pl-10 focus:ring-2 focus:ring-violet-500 focus:outline-none"
342
- aria-label="Search templates"
343
- />
344
- </div>
345
- <div className="flex flex-wrap gap-2">
346
- <button
347
- onClick={() => setSelectedTag(null)}
348
- className={`rounded-full px-4 py-2 text-sm font-medium transition-colors ${
349
- selectedTag === null
350
- ? 'bg-violet-500 text-white'
351
- : 'bg-card border-border hover:bg-card/80 border'
352
- }`}
353
- aria-pressed={selectedTag === null}
354
- >
355
- All
356
- </button>
357
- {allTags.map((tag) => (
358
- <button
359
- key={tag}
360
- onClick={() => setSelectedTag(tag)}
361
- className={cn(
362
- `rounded-full px-4 py-2 text-sm font-medium transition-colors`,
363
- {
364
- 'bg-violet-500 text-white': selectedTag === tag,
365
- 'bg-card border-border hover:bg-card/80 border':
366
- selectedTag !== tag,
367
- }
368
- )}
369
- aria-pressed={selectedTag === tag}
370
- >
371
- {tag}
372
- </button>
373
- ))}
374
- </div>
375
- </div>
376
- </section>
312
+ <section className="editorial-section">
313
+ <div className="editorial-shell space-y-6">
314
+ <div className="flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
315
+ <div className="max-w-3xl space-y-3">
316
+ <p className="editorial-kicker">Browse by source</p>
317
+ <h2 className="font-serif text-4xl tracking-[-0.04em]">
318
+ Use local scenarios for core proof, then scan the community.
319
+ </h2>
320
+ <p className="text-muted-foreground text-sm leading-7">
321
+ Local templates show the official adoption path. Community
322
+ templates show where the ecosystem is pushing the system next.
323
+ </p>
324
+ </div>
325
+ <div className="flex gap-2">
326
+ <button
327
+ onClick={() => setSource('local')}
328
+ className={cn(
329
+ 'rounded-full px-4 py-2 font-medium text-sm transition-colors',
330
+ {
331
+ 'bg-primary text-primary-foreground': source === 'local',
332
+ 'border border-border bg-card hover:bg-card/80':
333
+ source !== 'local',
334
+ }
335
+ )}
336
+ aria-pressed={source === 'local'}
337
+ >
338
+ Local
339
+ </button>
340
+ <button
341
+ onClick={() => setSource('registry')}
342
+ className={cn(
343
+ 'rounded-full px-4 py-2 font-medium text-sm transition-colors',
344
+ {
345
+ 'bg-primary text-primary-foreground':
346
+ source === 'registry',
347
+ 'border border-border bg-card hover:bg-card/80':
348
+ source !== 'registry',
349
+ }
350
+ )}
351
+ aria-pressed={source === 'registry'}
352
+ >
353
+ Community
354
+ </button>
355
+ </div>
356
+ </div>
357
+ <div className="editorial-panel space-y-5">
358
+ <div className="relative">
359
+ <Search
360
+ className="absolute top-3.5 left-4 text-muted-foreground"
361
+ size={18}
362
+ />
363
+ <input
364
+ type="text"
365
+ placeholder="Search scenarios, industries, or capabilities"
366
+ value={search}
367
+ onChange={(e) => setSearch(e.target.value)}
368
+ className="w-full rounded-full border border-border bg-background px-12 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
369
+ aria-label="Search templates"
370
+ />
371
+ </div>
372
+ <div className="flex flex-wrap gap-2">
373
+ <button
374
+ onClick={() => setSelectedTag(null)}
375
+ className={cn(
376
+ 'rounded-full px-4 py-2 font-medium text-sm transition-colors',
377
+ {
378
+ 'bg-primary text-primary-foreground':
379
+ selectedTag === null,
380
+ 'border border-border bg-card hover:bg-card/80':
381
+ selectedTag !== null,
382
+ }
383
+ )}
384
+ aria-pressed={selectedTag === null}
385
+ >
386
+ All
387
+ </button>
388
+ {allTags.map((tag) => (
389
+ <button
390
+ key={tag}
391
+ onClick={() => setSelectedTag(tag)}
392
+ className={cn(
393
+ 'rounded-full px-4 py-2 font-medium text-sm transition-colors',
394
+ {
395
+ 'bg-primary text-primary-foreground':
396
+ selectedTag === tag,
397
+ 'border border-border bg-card hover:bg-card/80':
398
+ selectedTag !== tag,
399
+ }
400
+ )}
401
+ aria-pressed={selectedTag === tag}
402
+ >
403
+ {tag}
404
+ </button>
405
+ ))}
406
+ </div>
407
+ </div>
408
+ </div>
409
+ </section>
377
410
 
378
- {/* Templates Grid */}
379
- <section className="section-padding">
380
- <div className="mx-auto max-w-6xl">
381
- {source === 'registry' ? (
382
- registryLoading ? (
383
- <div className="py-12 text-center">
384
- <p className="text-muted-foreground">
385
- Loading community templates…
386
- </p>
387
- </div>
388
- ) : registryTemplates.length === 0 ? (
389
- <div className="py-12 text-center">
390
- <p className="text-muted-foreground">
391
- No community templates found (configure
392
- `NEXT_PUBLIC_CONTRACTSPEC_REGISTRY_URL`).
393
- </p>
394
- </div>
395
- ) : (
396
- <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
397
- {registryTemplates.map((t) => (
398
- <div
399
- key={t.id}
400
- className="card-subtle relative flex flex-col space-y-4 p-6 transition-colors hover:border-violet-500/50"
401
- >
402
- <div>
403
- <h3 className="text-lg font-bold">{t.name}</h3>
404
- <p className="text-muted-foreground mt-1 text-sm">
405
- {t.description}
406
- </p>
407
- </div>
408
- <div className="flex-1 space-y-2">
409
- <div className="flex flex-wrap gap-1">
410
- {t.tags.map((tag) => (
411
- <span
412
- key={tag}
413
- className="rounded border border-violet-500/20 bg-violet-500/10 px-2 py-1 text-xs text-violet-300"
414
- >
415
- {tag}
416
- </span>
417
- ))}
418
- </div>
419
- </div>
420
- <div className="flex gap-2 pt-4">
421
- <Tooltip>
422
- <TooltipTrigger asChild>
423
- <button
424
- className="btn-ghost flex-1 text-center text-xs"
425
- onClick={() => {
426
- const local = getTemplate(t.id as TemplateId);
427
- if (!local) {
428
- setSelectedTemplateForCommand(t);
429
- return;
430
- }
431
- setPreview(t.id as TemplateId);
432
- }}
433
- >
434
- Preview
435
- </button>
436
- </TooltipTrigger>
437
- <TooltipContent>
438
- <p>Preview this template (if available locally)</p>
439
- </TooltipContent>
440
- </Tooltip>
441
- <Tooltip>
442
- <TooltipTrigger asChild>
443
- <button
444
- className="btn-primary flex-1 text-center text-xs"
445
- onClick={() => {
446
- captureAnalyticsEvent(
447
- analyticsEventNames.EXAMPLE_REPO_OPEN,
448
- {
449
- surface: 'templates',
450
- templateId: t.id,
451
- source: 'registry',
452
- }
453
- );
454
- setSelectedTemplateForCommand(t);
455
- }}
456
- >
457
- Use Template
458
- </button>
459
- </TooltipTrigger>
460
- <TooltipContent>
461
- <p>Get CLI command</p>
462
- </TooltipContent>
463
- </Tooltip>
464
- </div>
465
- </div>
466
- ))}
467
- </div>
468
- )
469
- ) : filtered.length === 0 ? (
470
- <div className="py-12 text-center">
471
- <p className="text-muted-foreground">
472
- No templates match your filters. Try a different search.
473
- </p>
474
- </div>
475
- ) : (
476
- <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
477
- {filtered.map((template, i) => (
478
- <div
479
- key={i}
480
- className="card-subtle relative flex flex-col space-y-4 p-6 transition-colors hover:border-violet-500/50"
481
- >
482
- {'isNew' in template && template.isNew && (
483
- <span className="absolute top-3 right-3 rounded-full bg-green-500 px-2 py-0.5 text-xs font-semibold text-white">
484
- New
485
- </span>
486
- )}
487
- <div>
488
- <h3 className="text-lg font-bold">{template.title}</h3>
489
- <p className="text-muted-foreground mt-1 text-sm">
490
- {template.description}
491
- </p>
492
- </div>
493
- <div className="flex-1 space-y-2">
494
- <p className="text-muted-foreground text-xs">
495
- <span className="text-foreground font-medium">
496
- Capabilities:
497
- </span>{' '}
498
- {template.capabilities}
499
- </p>
500
- <div className="flex flex-wrap gap-1">
501
- {template.tags.map((tag) => (
502
- <span
503
- key={tag}
504
- className="rounded border border-violet-500/20 bg-violet-500/10 px-2 py-1 text-xs text-violet-300"
505
- >
506
- {tag}
507
- </span>
508
- ))}
509
- </div>
510
- </div>
511
- <div className="flex gap-2 pt-4">
512
- <Tooltip>
513
- <TooltipTrigger asChild>
514
- <button
515
- className="btn-ghost flex-1 text-center text-xs"
516
- onClick={() => setPreview(template.templateId)}
517
- >
518
- Preview
519
- </button>
520
- </TooltipTrigger>
521
- <TooltipContent>
522
- <p>Preview this template in a modal</p>
523
- </TooltipContent>
524
- </Tooltip>
525
- <Tooltip>
526
- <TooltipTrigger asChild>
527
- <button
528
- className="btn-primary flex-1 text-center text-xs"
529
- onClick={() => {
530
- captureAnalyticsEvent(
531
- analyticsEventNames.EXAMPLE_REPO_OPEN,
532
- {
533
- surface: 'templates',
534
- templateId: template.templateId,
535
- source: 'local',
536
- }
537
- );
538
- setSelectedTemplateForCommand(template);
539
- }}
540
- >
541
- Use Template
542
- </button>
543
- </TooltipTrigger>
544
- <TooltipContent>
545
- <p>Get CLI command</p>
546
- </TooltipContent>
547
- </Tooltip>
548
- </div>
549
- </div>
550
- ))}
551
- </div>
552
- )}
553
- </div>
554
- </section>
411
+ <section className="section-padding">
412
+ <div className="editorial-shell">
413
+ {source === 'registry' ? (
414
+ registryLoading ? (
415
+ <div className="py-12 text-center">
416
+ <p className="text-muted-foreground">
417
+ Loading community templates…
418
+ </p>
419
+ </div>
420
+ ) : registryTemplates.length === 0 ? (
421
+ <div className="py-12 text-center">
422
+ <p className="text-muted-foreground">
423
+ No community templates found (configure
424
+ `NEXT_PUBLIC_CONTRACTSPEC_REGISTRY_URL`).
425
+ </p>
426
+ </div>
427
+ ) : (
428
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
429
+ {registryTemplates.map((t) => (
430
+ <div
431
+ key={t.id}
432
+ className="editorial-panel relative flex flex-col space-y-4 transition-colors hover:border-[color:rgb(162_79_42_/_0.55)]"
433
+ >
434
+ <div>
435
+ <h3 className="font-serif text-2xl tracking-[-0.03em]">
436
+ {t.name}
437
+ </h3>
438
+ <p className="mt-1 text-muted-foreground text-sm">
439
+ {t.description}
440
+ </p>
441
+ </div>
442
+ <div className="flex-1 space-y-2">
443
+ <div className="flex flex-wrap gap-1">
444
+ {t.tags.map((tag) => (
445
+ <span
446
+ key={tag}
447
+ className="rounded-full border border-border bg-muted px-3 py-1 text-[11px] text-muted-foreground"
448
+ >
449
+ {tag}
450
+ </span>
451
+ ))}
452
+ </div>
453
+ </div>
454
+ <div className="flex gap-2 pt-4">
455
+ <Tooltip>
456
+ <TooltipTrigger asChild>
457
+ <button
458
+ className="btn-ghost flex-1 text-center text-xs"
459
+ onClick={() => {
460
+ const local = getTemplate(t.id as TemplateId);
461
+ if (!local) {
462
+ setSelectedTemplateForCommand(t);
463
+ return;
464
+ }
465
+ setPreview(t.id as TemplateId);
466
+ }}
467
+ >
468
+ Preview
469
+ </button>
470
+ </TooltipTrigger>
471
+ <TooltipContent>
472
+ <p>Preview this template (if available locally)</p>
473
+ </TooltipContent>
474
+ </Tooltip>
475
+ <Tooltip>
476
+ <TooltipTrigger asChild>
477
+ <button
478
+ className="btn-primary flex-1 text-center text-xs"
479
+ onClick={() => {
480
+ captureAnalyticsEvent(
481
+ analyticsEventNames.EXAMPLE_REPO_OPEN,
482
+ {
483
+ surface: 'templates',
484
+ templateId: t.id,
485
+ source: 'registry',
486
+ }
487
+ );
488
+ setSelectedTemplateForCommand(t);
489
+ }}
490
+ >
491
+ Use Template
492
+ </button>
493
+ </TooltipTrigger>
494
+ <TooltipContent>
495
+ <p>Get CLI command</p>
496
+ </TooltipContent>
497
+ </Tooltip>
498
+ </div>
499
+ </div>
500
+ ))}
501
+ </div>
502
+ )
503
+ ) : filtered.length === 0 ? (
504
+ <div className="py-12 text-center">
505
+ <p className="text-muted-foreground">
506
+ No templates match your filters. Try a different search.
507
+ </p>
508
+ </div>
509
+ ) : (
510
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
511
+ {filtered.map((template, i) => (
512
+ <div
513
+ key={i}
514
+ className="editorial-panel relative flex flex-col space-y-4 transition-colors hover:border-[color:rgb(162_79_42_/_0.55)]"
515
+ >
516
+ {'isNew' in template && template.isNew && (
517
+ <span className="absolute top-4 right-4 rounded-full bg-[color:var(--success)] px-2.5 py-1 font-medium text-[11px] text-white uppercase">
518
+ New
519
+ </span>
520
+ )}
521
+ <div>
522
+ <h3 className="font-serif text-2xl tracking-[-0.03em]">
523
+ {template.title}
524
+ </h3>
525
+ <p className="mt-1 text-muted-foreground text-sm">
526
+ {template.description}
527
+ </p>
528
+ </div>
529
+ <div className="flex-1 space-y-2">
530
+ <p className="text-muted-foreground text-xs">
531
+ <span className="font-medium text-foreground">
532
+ Capabilities:
533
+ </span>{' '}
534
+ {template.capabilities}
535
+ </p>
536
+ <div className="flex flex-wrap gap-1">
537
+ {template.tags.map((tag) => (
538
+ <span
539
+ key={tag}
540
+ className="rounded-full border border-border bg-muted px-3 py-1 text-[11px] text-muted-foreground"
541
+ >
542
+ {tag}
543
+ </span>
544
+ ))}
545
+ </div>
546
+ </div>
547
+ <div className="flex gap-2 pt-4">
548
+ <Tooltip>
549
+ <TooltipTrigger asChild>
550
+ <button
551
+ className="btn-ghost flex-1 text-center text-xs"
552
+ onClick={() => setPreview(template.templateId)}
553
+ >
554
+ Preview
555
+ </button>
556
+ </TooltipTrigger>
557
+ <TooltipContent>
558
+ <p>Preview this template in a modal</p>
559
+ </TooltipContent>
560
+ </Tooltip>
561
+ <Tooltip>
562
+ <TooltipTrigger asChild>
563
+ <button
564
+ className="btn-primary flex-1 text-center text-xs"
565
+ onClick={() => {
566
+ captureAnalyticsEvent(
567
+ analyticsEventNames.EXAMPLE_REPO_OPEN,
568
+ {
569
+ surface: 'templates',
570
+ templateId: template.templateId,
571
+ source: 'local',
572
+ }
573
+ );
574
+ setSelectedTemplateForCommand(template);
575
+ }}
576
+ >
577
+ Use Template
578
+ </button>
579
+ </TooltipTrigger>
580
+ <TooltipContent>
581
+ <p>Get CLI command</p>
582
+ </TooltipContent>
583
+ </Tooltip>
584
+ </div>
585
+ </div>
586
+ ))}
587
+ </div>
588
+ )}
589
+ </div>
590
+ </section>
555
591
 
556
- {/* Extend with Integrations & Knowledge */}
557
- <section className="section-padding border-border bg-striped border-t">
558
- <div className="mx-auto max-w-6xl space-y-8">
559
- <div className="space-y-4 text-center">
560
- <h2 className="text-3xl font-bold md:text-4xl">
561
- Extend templates with integrations & knowledge
562
- </h2>
563
- <p className="text-muted-foreground mx-auto max-w-2xl">
564
- Every template can be enhanced with built-in integrations and
565
- knowledge spaces. Add payments, email, AI, and structured
566
- knowledge without writing integration code.
567
- </p>
568
- </div>
569
- <div className="grid gap-6 md:grid-cols-3">
570
- <div className="card-subtle space-y-4 p-6">
571
- <div className="text-3xl">💳</div>
572
- <h3 className="font-bold">Add Payments</h3>
573
- <p className="text-muted-foreground text-sm">
574
- Connect Stripe to any template for payment processing,
575
- subscriptions, and invoicing. Type-safe and policy-enforced.
576
- </p>
577
- <Link
578
- href="/docs/integrations/stripe"
579
- className="inline-flex items-center gap-1 text-sm text-violet-400 hover:text-violet-300"
580
- >
581
- Learn more
582
- </Link>
583
- </div>
584
- <div className="card-subtle space-y-4 p-6">
585
- <div className="text-3xl">📧</div>
586
- <h3 className="font-bold">Add Notifications</h3>
587
- <p className="text-muted-foreground text-sm">
588
- Send transactional emails via Postmark or Resend. Process
589
- inbound emails with Gmail API. SMS via Twilio.
590
- </p>
591
- <Link
592
- href="/docs/integrations"
593
- className="inline-flex items-center gap-1 text-sm text-violet-400 hover:text-violet-300"
594
- >
595
- View integrations →
596
- </Link>
597
- </div>
598
- <div className="card-subtle space-y-4 p-6">
599
- <div className="text-3xl">🧠</div>
600
- <h3 className="font-bold">Add AI & Knowledge</h3>
601
- <p className="text-muted-foreground text-sm">
602
- Power templates with OpenAI, vector search via Qdrant, and
603
- structured knowledge spaces for context-aware workflows.
604
- </p>
605
- <Link
606
- href="/docs/knowledge"
607
- className="inline-flex items-center gap-1 text-sm text-violet-400 hover:text-violet-300"
608
- >
609
- Learn about knowledge
610
- </Link>
611
- </div>
612
- </div>
613
- <div className="pt-4 text-center">
614
- <p className="text-muted-foreground mb-4 text-sm">
615
- All integrations are configured per-tenant with automatic health
616
- checks and credential rotation.
617
- </p>
618
- <Link href="/docs/architecture" className="btn-primary">
619
- View Architecture
620
- </Link>
621
- </div>
622
- </div>
623
- </section>
624
- </main>
592
+ <section className="editorial-section bg-striped">
593
+ <div className="editorial-shell space-y-8">
594
+ <div className="max-w-3xl space-y-4">
595
+ <p className="editorial-kicker">From template to real system</p>
596
+ <h2 className="font-serif text-4xl tracking-[-0.04em] md:text-5xl">
597
+ Templates become useful when the system can absorb more context.
598
+ </h2>
599
+ <p className="editorial-copy">
600
+ Use templates to prove the base flow, then layer integrations,
601
+ knowledge, and runtime behavior on top without losing the same
602
+ contract source.
603
+ </p>
604
+ </div>
605
+ <div className="grid gap-6 md:grid-cols-3">
606
+ <div className="editorial-panel space-y-4">
607
+ <div className="text-3xl">💳</div>
608
+ <h3 className="font-serif text-2xl tracking-[-0.03em]">
609
+ Add payments
610
+ </h3>
611
+ <p className="text-muted-foreground text-sm">
612
+ Connect Stripe to any template for payment processing,
613
+ subscriptions, and invoicing. Type-safe and policy-enforced.
614
+ </p>
615
+ <Link
616
+ href="/docs/integrations/stripe"
617
+ className="font-medium text-[color:var(--blue)] text-sm hover:opacity-80"
618
+ >
619
+ Learn more →
620
+ </Link>
621
+ </div>
622
+ <div className="editorial-panel space-y-4">
623
+ <div className="text-3xl">📧</div>
624
+ <h3 className="font-serif text-2xl tracking-[-0.03em]">
625
+ Add notifications
626
+ </h3>
627
+ <p className="text-muted-foreground text-sm">
628
+ Send transactional emails via Postmark or Resend. Process
629
+ inbound emails with Gmail API. SMS via Twilio.
630
+ </p>
631
+ <Link
632
+ href="/docs/integrations"
633
+ className="font-medium text-[color:var(--blue)] text-sm hover:opacity-80"
634
+ >
635
+ View integrations →
636
+ </Link>
637
+ </div>
638
+ <div className="editorial-panel space-y-4">
639
+ <div className="text-3xl">🧠</div>
640
+ <h3 className="font-serif text-2xl tracking-[-0.03em]">
641
+ Add AI and knowledge
642
+ </h3>
643
+ <p className="text-muted-foreground text-sm">
644
+ Power templates with OpenAI, vector search via Qdrant, and
645
+ structured knowledge spaces for context-aware workflows.
646
+ </p>
647
+ <Link
648
+ href="/docs/knowledge"
649
+ className="font-medium text-[color:var(--blue)] text-sm hover:opacity-80"
650
+ >
651
+ Learn about knowledge
652
+ </Link>
653
+ </div>
654
+ </div>
655
+ <div className="pt-4 text-center">
656
+ <p className="mb-4 text-muted-foreground text-sm">
657
+ All integrations are configured per-tenant with automatic health
658
+ checks and credential rotation.
659
+ </p>
660
+ <Link href="/docs/architecture" className="btn-primary">
661
+ View Architecture
662
+ </Link>
663
+ </div>
664
+ </div>
665
+ </section>
666
+ </main>
625
667
 
626
- {/*{preview ? (*/}
627
- <TemplatePreviewModal
628
- templateId={preview}
629
- onClose={() => {
630
- setPreview(null);
631
- }}
632
- />
633
- {/*) : null}*/}
668
+ {/*{preview ? (*/}
669
+ <TemplatePreviewModal
670
+ templateId={preview}
671
+ onClose={() => {
672
+ setPreview(null);
673
+ }}
674
+ />
675
+ {/*) : null}*/}
634
676
 
635
- <Dialog
636
- open={studioSignupModalOpen}
637
- onOpenChange={setStudioSignupModalOpen}
638
- >
639
- <DialogContent className="max-h-[90vh] max-w-2xl overflow-y-auto">
640
- <DialogHeader>
641
- <DialogTitle>Deploy in Studio</DialogTitle>
642
- <DialogDescription>
643
- Deploy templates in ContractSpec Studio and run the full
644
- evidence-to-spec loop with your team.
645
- </DialogDescription>
646
- </DialogHeader>
647
- <StudioSignupSection variant="compact" />
648
- </DialogContent>
649
- </Dialog>
677
+ <Dialog
678
+ open={studioSignupModalOpen}
679
+ onOpenChange={setStudioSignupModalOpen}
680
+ >
681
+ <DialogContent className="max-h-[90vh] max-w-2xl overflow-y-auto">
682
+ <DialogHeader>
683
+ <DialogTitle>Deploy in Studio</DialogTitle>
684
+ <DialogDescription>
685
+ Deploy templates in ContractSpec Studio and run the full
686
+ evidence-to-spec loop with your team.
687
+ </DialogDescription>
688
+ </DialogHeader>
689
+ <StudioSignupSection variant="compact" />
690
+ </DialogContent>
691
+ </Dialog>
650
692
 
651
- <Dialog
652
- open={!!selectedTemplateForCommand}
653
- onOpenChange={() => setSelectedTemplateForCommand(null)}
654
- >
655
- <DialogContent className="max-w-md">
656
- <DialogHeader>
657
- <DialogTitle>Use this template</DialogTitle>
658
- <DialogDescription>
659
- Initialize a new project with this template using the CLI.
660
- </DialogDescription>
661
- </DialogHeader>
662
- <div className="space-y-4 pt-4">
663
- <div className="rounded-md border border-zinc-800 bg-zinc-950 p-4 font-mono text-sm text-zinc-50">
664
- npx contractspec init --template {commandId}
665
- </div>
666
- <div className="flex gap-2">
667
- <button
668
- className="btn-secondary w-full"
669
- onClick={() => {
670
- navigator.clipboard.writeText(
671
- `npx contractspec init --template ${commandId}`
672
- );
673
- captureAnalyticsEvent(
674
- analyticsEventNames.COPY_COMMAND_CLICK,
675
- {
676
- surface: 'templates',
677
- templateId: commandId,
678
- filename: 'templates-cli',
679
- }
680
- );
681
- }}
682
- >
683
- Copy Command
684
- </button>
685
- </div>
686
- <div className="relative">
687
- <div className="absolute inset-0 flex items-center">
688
- <span className="border-border w-full border-t" />
689
- </div>
690
- <div className="relative flex justify-center text-xs uppercase">
691
- <span className="bg-background text-muted-foreground px-2">
692
- Or
693
- </span>
694
- </div>
695
- </div>
696
- <button
697
- className="btn-ghost w-full text-sm"
698
- onClick={() => {
699
- captureAnalyticsEvent(analyticsEventNames.CTA_STUDIO_CLICK, {
700
- surface: 'templates',
701
- templateId: commandId,
702
- });
703
- setSelectedTemplateForCommand(null);
704
- setStudioSignupModalOpen(true);
705
- }}
706
- >
707
- Deploy to Studio
708
- </button>
709
- </div>
710
- </DialogContent>
711
- </Dialog>
712
- </TooltipProvider>
713
- );
693
+ <Dialog
694
+ open={!!selectedTemplateForCommand}
695
+ onOpenChange={() => setSelectedTemplateForCommand(null)}
696
+ >
697
+ <DialogContent className="max-w-md">
698
+ <DialogHeader>
699
+ <DialogTitle>Use this template</DialogTitle>
700
+ <DialogDescription>
701
+ Initialize a new project with this template using the CLI.
702
+ </DialogDescription>
703
+ </DialogHeader>
704
+ <div className="space-y-4 pt-4">
705
+ <div className="rounded-md border border-zinc-800 bg-zinc-950 p-4 font-mono text-sm text-zinc-50">
706
+ npx contractspec init --template {commandId}
707
+ </div>
708
+ <div className="flex gap-2">
709
+ <button
710
+ className="btn-secondary w-full"
711
+ onClick={() => {
712
+ navigator.clipboard.writeText(
713
+ `npx contractspec init --template ${commandId}`
714
+ );
715
+ captureAnalyticsEvent(
716
+ analyticsEventNames.COPY_COMMAND_CLICK,
717
+ {
718
+ surface: 'templates',
719
+ templateId: commandId,
720
+ filename: 'templates-cli',
721
+ }
722
+ );
723
+ }}
724
+ >
725
+ Copy Command
726
+ </button>
727
+ </div>
728
+ <div className="relative">
729
+ <div className="absolute inset-0 flex items-center">
730
+ <span className="w-full border-border border-t" />
731
+ </div>
732
+ <div className="relative flex justify-center text-xs uppercase">
733
+ <span className="bg-background px-2 text-muted-foreground">
734
+ Or
735
+ </span>
736
+ </div>
737
+ </div>
738
+ <button
739
+ className="btn-ghost w-full text-sm"
740
+ onClick={() => {
741
+ captureAnalyticsEvent(analyticsEventNames.CTA_STUDIO_CLICK, {
742
+ surface: 'templates',
743
+ templateId: commandId,
744
+ });
745
+ setSelectedTemplateForCommand(null);
746
+ setStudioSignupModalOpen(true);
747
+ }}
748
+ >
749
+ Deploy to Studio
750
+ </button>
751
+ </div>
752
+ </DialogContent>
753
+ </Dialog>
754
+ </TooltipProvider>
755
+ );
714
756
  };