@contractspec/bundle.marketing 3.8.9 → 3.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +54 -42
- package/CHANGELOG.md +33 -0
- package/dist/browser/components/templates/TemplatesBrowseControls.js +37 -22
- package/dist/browser/components/templates/TemplatesCatalogSection.js +29 -6
- package/dist/browser/components/templates/TemplatesClientPage.js +269 -89
- package/dist/browser/components/templates/TemplatesOverlays.js +2874 -0
- package/dist/browser/components/templates/index.js +301 -121
- package/dist/browser/components/templates/template-catalog.js +5 -3
- package/dist/browser/components/templates/template-filters.js +99 -0
- package/dist/browser/components/templates/template-tag-visibility.js +40 -0
- package/dist/browser/components/templates/useTemplateBrowseState.js +191 -0
- package/dist/browser/index.js +301 -121
- package/dist/components/templates/TemplatesBrowseControls.d.ts +7 -2
- package/dist/components/templates/TemplatesBrowseControls.js +37 -22
- package/dist/components/templates/TemplatesCatalogSection.d.ts +4 -1
- package/dist/components/templates/TemplatesCatalogSection.js +29 -6
- package/dist/components/templates/TemplatesClientPage.js +269 -89
- package/dist/components/templates/TemplatesOverlays.d.ts +10 -0
- package/dist/components/templates/TemplatesOverlays.js +2869 -0
- package/dist/components/templates/index.js +301 -121
- package/dist/components/templates/template-catalog.d.ts +1 -0
- package/dist/components/templates/template-catalog.js +5 -3
- package/dist/components/templates/template-filters.d.ts +12 -0
- package/dist/components/templates/template-filters.js +94 -0
- package/dist/components/templates/template-tag-visibility.d.ts +10 -0
- package/dist/components/templates/template-tag-visibility.js +35 -0
- package/dist/components/templates/useTemplateBrowseState.d.ts +22 -0
- package/dist/components/templates/useTemplateBrowseState.js +186 -0
- package/dist/index.js +301 -121
- package/dist/node/components/templates/TemplatesBrowseControls.js +37 -22
- package/dist/node/components/templates/TemplatesCatalogSection.js +29 -6
- package/dist/node/components/templates/TemplatesClientPage.js +269 -89
- package/dist/node/components/templates/TemplatesOverlays.js +2869 -0
- package/dist/node/components/templates/index.js +301 -121
- package/dist/node/components/templates/template-catalog.js +5 -3
- package/dist/node/components/templates/template-filters.js +94 -0
- package/dist/node/components/templates/template-tag-visibility.js +35 -0
- package/dist/node/components/templates/useTemplateBrowseState.js +186 -0
- package/dist/node/index.js +301 -121
- package/package.json +82 -26
- package/src/components/templates/TemplatesBrowseControls.tsx +59 -35
- package/src/components/templates/TemplatesCatalogSection.tsx +29 -4
- package/src/components/templates/TemplatesClientPage.tsx +41 -97
- package/src/components/templates/TemplatesOverlays.tsx +65 -0
- package/src/components/templates/template-catalog.test.ts +96 -0
- package/src/components/templates/template-catalog.ts +14 -6
- package/src/components/templates/template-filters.ts +57 -0
- package/src/components/templates/template-tag-visibility.ts +58 -0
- package/src/components/templates/useTemplateBrowseState.ts +101 -0
|
@@ -0,0 +1,2869 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/components/marketing/ChangelogPage.tsx
|
|
5
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
6
|
+
function ChangelogPage({ entries }) {
|
|
7
|
+
return /* @__PURE__ */ jsxDEV("main", {
|
|
8
|
+
children: [
|
|
9
|
+
/* @__PURE__ */ jsxDEV("section", {
|
|
10
|
+
className: "section-padding hero-gradient relative border-border border-b",
|
|
11
|
+
children: /* @__PURE__ */ jsxDEV("div", {
|
|
12
|
+
className: "mx-auto max-w-4xl space-y-6 text-center",
|
|
13
|
+
children: [
|
|
14
|
+
/* @__PURE__ */ jsxDEV("h1", {
|
|
15
|
+
className: "font-bold text-5xl leading-tight md:text-6xl",
|
|
16
|
+
children: "Changelog"
|
|
17
|
+
}, undefined, false, undefined, this),
|
|
18
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
19
|
+
className: "text-lg text-muted-foreground",
|
|
20
|
+
children: "Latest releases and improvements to ContractSpec."
|
|
21
|
+
}, undefined, false, undefined, this)
|
|
22
|
+
]
|
|
23
|
+
}, undefined, true, undefined, this)
|
|
24
|
+
}, undefined, false, undefined, this),
|
|
25
|
+
/* @__PURE__ */ jsxDEV("section", {
|
|
26
|
+
className: "section-padding",
|
|
27
|
+
children: /* @__PURE__ */ jsxDEV("div", {
|
|
28
|
+
className: "mx-auto max-w-3xl space-y-8",
|
|
29
|
+
children: entries.map((entry, i) => /* @__PURE__ */ jsxDEV("div", {
|
|
30
|
+
className: "card-subtle flex flex-col gap-6 p-8 md:flex-row md:items-start",
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
33
|
+
className: "md:w-48 md:flex-shrink-0",
|
|
34
|
+
children: /* @__PURE__ */ jsxDEV("div", {
|
|
35
|
+
className: "sticky top-24",
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ jsxDEV("h3", {
|
|
38
|
+
className: "font-bold text-2xl tracking-tight",
|
|
39
|
+
children: entry.version
|
|
40
|
+
}, undefined, false, undefined, this),
|
|
41
|
+
/* @__PURE__ */ jsxDEV("time", {
|
|
42
|
+
className: "mt-1 block font-medium text-muted-foreground text-sm",
|
|
43
|
+
children: entry.date
|
|
44
|
+
}, undefined, false, undefined, this),
|
|
45
|
+
entry.isBreaking && /* @__PURE__ */ jsxDEV("span", {
|
|
46
|
+
className: "mt-2 inline-flex items-center rounded-full border border-red-500/50 bg-red-500/10 px-2.5 py-0.5 font-semibold text-red-500 text-xs",
|
|
47
|
+
children: "Breaking Change"
|
|
48
|
+
}, undefined, false, undefined, this)
|
|
49
|
+
]
|
|
50
|
+
}, undefined, true, undefined, this)
|
|
51
|
+
}, undefined, false, undefined, this),
|
|
52
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
53
|
+
className: "flex-1 space-y-6",
|
|
54
|
+
children: entry.packages.map((pkg, j) => /* @__PURE__ */ jsxDEV("div", {
|
|
55
|
+
className: "space-y-3",
|
|
56
|
+
children: [
|
|
57
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
58
|
+
className: "font-mono font-semibold text-sm text-violet-400",
|
|
59
|
+
children: pkg.name
|
|
60
|
+
}, undefined, false, undefined, this),
|
|
61
|
+
/* @__PURE__ */ jsxDEV("ul", {
|
|
62
|
+
className: "space-y-2",
|
|
63
|
+
children: pkg.changes.map((change, k) => /* @__PURE__ */ jsxDEV("li", {
|
|
64
|
+
className: "flex items-start gap-3 text-base text-muted-foreground leading-relaxed",
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
67
|
+
className: "mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full bg-violet-500/50"
|
|
68
|
+
}, undefined, false, undefined, this),
|
|
69
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
70
|
+
children: change
|
|
71
|
+
}, undefined, false, undefined, this)
|
|
72
|
+
]
|
|
73
|
+
}, k, true, undefined, this))
|
|
74
|
+
}, undefined, false, undefined, this)
|
|
75
|
+
]
|
|
76
|
+
}, j, true, undefined, this))
|
|
77
|
+
}, undefined, false, undefined, this)
|
|
78
|
+
]
|
|
79
|
+
}, i, true, undefined, this))
|
|
80
|
+
}, undefined, false, undefined, this)
|
|
81
|
+
}, undefined, false, undefined, this)
|
|
82
|
+
]
|
|
83
|
+
}, undefined, true, undefined, this);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/components/marketing/CofounderPage.tsx
|
|
87
|
+
import Link from "next/link";
|
|
88
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
89
|
+
"use client";
|
|
90
|
+
var COFOUNDER_EMAIL = "tboutron@contractspec.io";
|
|
91
|
+
var APPLY_SUBJECT = "Co-founder application: ContractSpec";
|
|
92
|
+
var APPLY_BODY = `Hi Theo,
|
|
93
|
+
|
|
94
|
+
I am reaching out about co-founding ContractSpec.
|
|
95
|
+
|
|
96
|
+
LinkedIn: [your link]
|
|
97
|
+
Proof of work #1: [link]
|
|
98
|
+
Proof of work #2: [link]
|
|
99
|
+
|
|
100
|
+
Why ContractSpec:
|
|
101
|
+
[your answer]
|
|
102
|
+
|
|
103
|
+
What I would own in the first 90 days:
|
|
104
|
+
[your answer]
|
|
105
|
+
`;
|
|
106
|
+
var mailtoLink = `mailto:${COFOUNDER_EMAIL}?subject=${encodeURIComponent(APPLY_SUBJECT)}&body=${encodeURIComponent(APPLY_BODY)}`;
|
|
107
|
+
var tracks = [
|
|
108
|
+
{
|
|
109
|
+
title: "GTM / partnerships",
|
|
110
|
+
copy: "Own the design partner pipeline, sharpen messaging, and turn market feedback into product signal."
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
title: "Product / design",
|
|
114
|
+
copy: "Own the Studio surface, shape the interaction model, and turn live user behavior into clearer workflows."
|
|
115
|
+
}
|
|
116
|
+
];
|
|
117
|
+
function CofounderPage() {
|
|
118
|
+
return /* @__PURE__ */ jsxDEV2("main", {
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsxDEV2("section", {
|
|
121
|
+
className: "section-padding hero-gradient border-border/70 border-b",
|
|
122
|
+
children: /* @__PURE__ */ jsxDEV2("div", {
|
|
123
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[1.05fr_0.95fr]",
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
126
|
+
className: "space-y-5",
|
|
127
|
+
children: [
|
|
128
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
129
|
+
className: "editorial-kicker",
|
|
130
|
+
children: "Co-founder search"
|
|
131
|
+
}, undefined, false, undefined, this),
|
|
132
|
+
/* @__PURE__ */ jsxDEV2("h1", {
|
|
133
|
+
className: "editorial-title max-w-4xl",
|
|
134
|
+
children: "Looking for a co-founder who wants to build an open system and the product on top of it."
|
|
135
|
+
}, undefined, false, undefined, this),
|
|
136
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
137
|
+
className: "editorial-subtitle",
|
|
138
|
+
children: "ContractSpec already has the early stack shape: explicit contracts, runtimes, harnesses, examples, and the first Studio operating loops. The next phase needs someone who can own either GTM or product depth with real execution energy."
|
|
139
|
+
}, undefined, false, undefined, this)
|
|
140
|
+
]
|
|
141
|
+
}, undefined, true, undefined, this),
|
|
142
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
143
|
+
className: "editorial-panel space-y-5",
|
|
144
|
+
children: [
|
|
145
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
146
|
+
className: "editorial-kicker",
|
|
147
|
+
children: "What exists now"
|
|
148
|
+
}, undefined, false, undefined, this),
|
|
149
|
+
/* @__PURE__ */ jsxDEV2("ul", {
|
|
150
|
+
className: "editorial-list",
|
|
151
|
+
children: [
|
|
152
|
+
/* @__PURE__ */ jsxDEV2("li", {
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
155
|
+
className: "editorial-list-marker"
|
|
156
|
+
}, undefined, false, undefined, this),
|
|
157
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
158
|
+
children: "Open-source package ecosystem and working website/docs surface."
|
|
159
|
+
}, undefined, false, undefined, this)
|
|
160
|
+
]
|
|
161
|
+
}, undefined, true, undefined, this),
|
|
162
|
+
/* @__PURE__ */ jsxDEV2("li", {
|
|
163
|
+
children: [
|
|
164
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
165
|
+
className: "editorial-list-marker"
|
|
166
|
+
}, undefined, false, undefined, this),
|
|
167
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
168
|
+
children: "Studio product direction with live operating workflows."
|
|
169
|
+
}, undefined, false, undefined, this)
|
|
170
|
+
]
|
|
171
|
+
}, undefined, true, undefined, this),
|
|
172
|
+
/* @__PURE__ */ jsxDEV2("li", {
|
|
173
|
+
children: [
|
|
174
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
175
|
+
className: "editorial-list-marker"
|
|
176
|
+
}, undefined, false, undefined, this),
|
|
177
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
178
|
+
children: "Founder-led product, bootstrapped, still early enough to shape."
|
|
179
|
+
}, undefined, false, undefined, this)
|
|
180
|
+
]
|
|
181
|
+
}, undefined, true, undefined, this)
|
|
182
|
+
]
|
|
183
|
+
}, undefined, true, undefined, this),
|
|
184
|
+
/* @__PURE__ */ jsxDEV2(Link, {
|
|
185
|
+
href: mailtoLink,
|
|
186
|
+
className: "btn-primary",
|
|
187
|
+
children: "Talk about co-founding"
|
|
188
|
+
}, undefined, false, undefined, this)
|
|
189
|
+
]
|
|
190
|
+
}, undefined, true, undefined, this)
|
|
191
|
+
]
|
|
192
|
+
}, undefined, true, undefined, this)
|
|
193
|
+
}, undefined, false, undefined, this),
|
|
194
|
+
/* @__PURE__ */ jsxDEV2("section", {
|
|
195
|
+
className: "editorial-section",
|
|
196
|
+
children: /* @__PURE__ */ jsxDEV2("div", {
|
|
197
|
+
className: "editorial-shell grid gap-6 lg:grid-cols-2",
|
|
198
|
+
children: tracks.map((track) => /* @__PURE__ */ jsxDEV2("div", {
|
|
199
|
+
className: "editorial-panel",
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
202
|
+
className: "editorial-kicker",
|
|
203
|
+
children: track.title
|
|
204
|
+
}, undefined, false, undefined, this),
|
|
205
|
+
/* @__PURE__ */ jsxDEV2("h2", {
|
|
206
|
+
className: "mt-3 font-serif text-4xl tracking-[-0.04em]",
|
|
207
|
+
children: track.title
|
|
208
|
+
}, undefined, false, undefined, this),
|
|
209
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
210
|
+
className: "mt-4 text-muted-foreground text-sm leading-7",
|
|
211
|
+
children: track.copy
|
|
212
|
+
}, undefined, false, undefined, this)
|
|
213
|
+
]
|
|
214
|
+
}, track.title, true, undefined, this))
|
|
215
|
+
}, undefined, false, undefined, this)
|
|
216
|
+
}, undefined, false, undefined, this),
|
|
217
|
+
/* @__PURE__ */ jsxDEV2("section", {
|
|
218
|
+
className: "editorial-section bg-striped",
|
|
219
|
+
children: /* @__PURE__ */ jsxDEV2("div", {
|
|
220
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-2",
|
|
221
|
+
children: [
|
|
222
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
223
|
+
className: "editorial-panel",
|
|
224
|
+
children: [
|
|
225
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
226
|
+
className: "editorial-kicker",
|
|
227
|
+
children: "What good looks like"
|
|
228
|
+
}, undefined, false, undefined, this),
|
|
229
|
+
/* @__PURE__ */ jsxDEV2("ul", {
|
|
230
|
+
className: "editorial-list mt-6",
|
|
231
|
+
children: [
|
|
232
|
+
/* @__PURE__ */ jsxDEV2("li", {
|
|
233
|
+
children: [
|
|
234
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
235
|
+
className: "editorial-list-marker"
|
|
236
|
+
}, undefined, false, undefined, this),
|
|
237
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
238
|
+
children: "You have proof of work, not just interest."
|
|
239
|
+
}, undefined, false, undefined, this)
|
|
240
|
+
]
|
|
241
|
+
}, undefined, true, undefined, this),
|
|
242
|
+
/* @__PURE__ */ jsxDEV2("li", {
|
|
243
|
+
children: [
|
|
244
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
245
|
+
className: "editorial-list-marker"
|
|
246
|
+
}, undefined, false, undefined, this),
|
|
247
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
248
|
+
children: "You can own a whole surface and move without waiting for permission."
|
|
249
|
+
}, undefined, false, undefined, this)
|
|
250
|
+
]
|
|
251
|
+
}, undefined, true, undefined, this),
|
|
252
|
+
/* @__PURE__ */ jsxDEV2("li", {
|
|
253
|
+
children: [
|
|
254
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
255
|
+
className: "editorial-list-marker"
|
|
256
|
+
}, undefined, false, undefined, this),
|
|
257
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
258
|
+
children: "You like written clarity, sharp product taste, and direct feedback."
|
|
259
|
+
}, undefined, false, undefined, this)
|
|
260
|
+
]
|
|
261
|
+
}, undefined, true, undefined, this)
|
|
262
|
+
]
|
|
263
|
+
}, undefined, true, undefined, this)
|
|
264
|
+
]
|
|
265
|
+
}, undefined, true, undefined, this),
|
|
266
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
267
|
+
className: "editorial-panel",
|
|
268
|
+
children: [
|
|
269
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
270
|
+
className: "editorial-kicker",
|
|
271
|
+
children: "Apply"
|
|
272
|
+
}, undefined, false, undefined, this),
|
|
273
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
274
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
275
|
+
children: "Send links that prove how you think and how you ship. The best applications make it obvious what you would own in the first 90 days and why this problem is worth years of your attention."
|
|
276
|
+
}, undefined, false, undefined, this),
|
|
277
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
278
|
+
className: "mt-6 flex flex-col gap-3 sm:flex-row",
|
|
279
|
+
children: [
|
|
280
|
+
/* @__PURE__ */ jsxDEV2(Link, {
|
|
281
|
+
href: mailtoLink,
|
|
282
|
+
className: "btn-primary",
|
|
283
|
+
children: "Email application"
|
|
284
|
+
}, undefined, false, undefined, this),
|
|
285
|
+
/* @__PURE__ */ jsxDEV2(Link, {
|
|
286
|
+
href: "/contact",
|
|
287
|
+
className: "btn-ghost",
|
|
288
|
+
children: "Start with a conversation"
|
|
289
|
+
}, undefined, false, undefined, this)
|
|
290
|
+
]
|
|
291
|
+
}, undefined, true, undefined, this)
|
|
292
|
+
]
|
|
293
|
+
}, undefined, true, undefined, this)
|
|
294
|
+
]
|
|
295
|
+
}, undefined, true, undefined, this)
|
|
296
|
+
}, undefined, false, undefined, this)
|
|
297
|
+
]
|
|
298
|
+
}, undefined, true, undefined, this);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/libs/email/client.ts
|
|
302
|
+
import { Logger } from "@contractspec/lib.logger";
|
|
303
|
+
import { createClient, Temv1alpha1 } from "@scaleway/sdk";
|
|
304
|
+
var DEFAULT_FROM = {
|
|
305
|
+
email: "noreply@transactional.contractspec.io",
|
|
306
|
+
name: "ContractSpec"
|
|
307
|
+
};
|
|
308
|
+
var DEFAULT_TEAM_INBOX = {
|
|
309
|
+
email: "contact@contractspec.io",
|
|
310
|
+
name: "ContractSpec Team"
|
|
311
|
+
};
|
|
312
|
+
var DEFAULT_REGION = "fr-par";
|
|
313
|
+
var cachedConfig = null;
|
|
314
|
+
var cachedClient = null;
|
|
315
|
+
var apiFactory = (client) => new Temv1alpha1.API(client);
|
|
316
|
+
var mapRegion = (value) => {
|
|
317
|
+
const normalized = value?.trim().toLowerCase();
|
|
318
|
+
if (normalized === "par" || normalized === "fr-par")
|
|
319
|
+
return "fr-par";
|
|
320
|
+
if (normalized === "ams" || normalized === "nl-ams")
|
|
321
|
+
return "nl-ams";
|
|
322
|
+
if (normalized === "waw" || normalized === "pl-waw")
|
|
323
|
+
return "pl-waw";
|
|
324
|
+
return DEFAULT_REGION;
|
|
325
|
+
};
|
|
326
|
+
var getEmailConfig = () => {
|
|
327
|
+
if (cachedConfig) {
|
|
328
|
+
return { ok: true, config: cachedConfig };
|
|
329
|
+
}
|
|
330
|
+
const accessKey = process.env.SCALEWAY_ACCESS_KEY || process.env.SCALEWAY_ACCESS_KEY_QUEUE;
|
|
331
|
+
const secretKey = process.env.SCALEWAY_SECRET_KEY || process.env.SCALEWAY_SECRET_KEY_QUEUE;
|
|
332
|
+
const projectId = process.env.SCALEWAY_PROJECT_ID;
|
|
333
|
+
if (!accessKey || !secretKey || !projectId) {
|
|
334
|
+
return {
|
|
335
|
+
ok: false,
|
|
336
|
+
errorMessage: "Email service is not configured. Please contact us directly at contact@contractspec.io."
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const region = mapRegion(process.env.SCALEWAY_REGION);
|
|
340
|
+
cachedConfig = {
|
|
341
|
+
accessKey,
|
|
342
|
+
secretKey,
|
|
343
|
+
projectId,
|
|
344
|
+
region,
|
|
345
|
+
defaultZone: `${region}-1`,
|
|
346
|
+
from: {
|
|
347
|
+
email: process.env.SCALEWAY_EMAIL_FROM_EMAIL ?? DEFAULT_FROM.email,
|
|
348
|
+
name: process.env.SCALEWAY_EMAIL_FROM_NAME ?? DEFAULT_FROM.name
|
|
349
|
+
},
|
|
350
|
+
teamInbox: {
|
|
351
|
+
email: process.env.SCALEWAY_EMAIL_TEAM_EMAIL ?? DEFAULT_TEAM_INBOX.email,
|
|
352
|
+
name: process.env.SCALEWAY_EMAIL_TEAM_NAME ?? DEFAULT_TEAM_INBOX.name
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
return { ok: true, config: cachedConfig };
|
|
356
|
+
};
|
|
357
|
+
var getTemClient = (config) => {
|
|
358
|
+
if (cachedClient) {
|
|
359
|
+
return cachedClient;
|
|
360
|
+
}
|
|
361
|
+
const client = createClient({
|
|
362
|
+
accessKey: config.accessKey,
|
|
363
|
+
secretKey: config.secretKey,
|
|
364
|
+
defaultProjectId: config.projectId,
|
|
365
|
+
defaultRegion: config.region,
|
|
366
|
+
defaultZone: config.defaultZone
|
|
367
|
+
});
|
|
368
|
+
cachedClient = apiFactory(client);
|
|
369
|
+
return cachedClient;
|
|
370
|
+
};
|
|
371
|
+
var sendEmail = async (config, request) => {
|
|
372
|
+
try {
|
|
373
|
+
const client = getTemClient(config);
|
|
374
|
+
await client.createEmail({
|
|
375
|
+
region: config.region,
|
|
376
|
+
projectId: config.projectId,
|
|
377
|
+
from: config.from,
|
|
378
|
+
to: request.to,
|
|
379
|
+
subject: request.subject,
|
|
380
|
+
text: request.text,
|
|
381
|
+
html: request.html || request.text,
|
|
382
|
+
additionalHeaders: request.replyTo ? [{ key: "Reply-To", value: request.replyTo }] : undefined
|
|
383
|
+
});
|
|
384
|
+
return { success: true };
|
|
385
|
+
} catch (error) {
|
|
386
|
+
new Logger().error("scaleway_tem_email_send_failed", {
|
|
387
|
+
context: request.context ?? "email",
|
|
388
|
+
error: error instanceof Error ? error.message : error
|
|
389
|
+
});
|
|
390
|
+
return {
|
|
391
|
+
success: false,
|
|
392
|
+
error,
|
|
393
|
+
errorMessage: "Failed to send email via Scaleway."
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
var __internal = {
|
|
398
|
+
resetCaches() {
|
|
399
|
+
cachedClient = null;
|
|
400
|
+
cachedConfig = null;
|
|
401
|
+
apiFactory = (client) => new Temv1alpha1.API(client);
|
|
402
|
+
},
|
|
403
|
+
setApiFactory(factory) {
|
|
404
|
+
apiFactory = factory;
|
|
405
|
+
},
|
|
406
|
+
setClient(client) {
|
|
407
|
+
cachedClient = client;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// src/libs/email/utils.ts
|
|
412
|
+
var escapeHtml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
413
|
+
var formatMultilineHtml = (value) => escapeHtml(value).replaceAll(`
|
|
414
|
+
`, "<br />");
|
|
415
|
+
|
|
416
|
+
// src/libs/email/contact.ts
|
|
417
|
+
"use server";
|
|
418
|
+
var CONTACT_MISSING_CONFIG = "Email service is not configured. Please contact us directly at contact@contractspec.io.";
|
|
419
|
+
var CONTACT_SEND_ERROR = "Failed to send message. Please contact us directly at contact@contractspec.io.";
|
|
420
|
+
var submitContactForm = async (formData) => {
|
|
421
|
+
const name = (formData.get("name") ?? "").toString().trim();
|
|
422
|
+
const email = (formData.get("email") ?? "").toString().trim();
|
|
423
|
+
const message = (formData.get("message") ?? "").toString().trim();
|
|
424
|
+
if (!email) {
|
|
425
|
+
return {
|
|
426
|
+
success: false,
|
|
427
|
+
text: "Please fill in all required fields."
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
const configResult = getEmailConfig();
|
|
431
|
+
if (!configResult.ok || !configResult.config) {
|
|
432
|
+
return {
|
|
433
|
+
success: false,
|
|
434
|
+
text: configResult.errorMessage ?? CONTACT_MISSING_CONFIG
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
const senderName = name || email;
|
|
438
|
+
const emailContentText = `
|
|
439
|
+
New contact form submission from ${senderName}
|
|
440
|
+
|
|
441
|
+
Contact Information:
|
|
442
|
+
- Name: ${name || "Not provided"}
|
|
443
|
+
- Email: ${email}
|
|
444
|
+
|
|
445
|
+
Message:
|
|
446
|
+
${message || "No message provided"}
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
Submitted via ContractSpec contact form
|
|
450
|
+
`.trim();
|
|
451
|
+
const emailContentHtml = `
|
|
452
|
+
<div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
|
|
453
|
+
<h1 style="color: #8b5cf6; margin-bottom: 12px;">New contact form submission</h1>
|
|
454
|
+
<p style="margin: 0 0 12px;">From ${escapeHtml(senderName)}</p>
|
|
455
|
+
<h2 style="color: #8b5cf6; margin: 16px 0 8px;">Contact Information</h2>
|
|
456
|
+
<ul style="padding-left: 16px; line-height: 1.6; margin: 0 0 16px;">
|
|
457
|
+
<li>Name: ${escapeHtml(name || "Not provided")}</li>
|
|
458
|
+
<li>Email: ${escapeHtml(email)}</li>
|
|
459
|
+
</ul>
|
|
460
|
+
<h2 style="color: #8b5cf6; margin: 16px 0 8px;">Message</h2>
|
|
461
|
+
<div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;">
|
|
462
|
+
${message ? formatMultilineHtml(message) : "No message provided"}
|
|
463
|
+
</div>
|
|
464
|
+
<p style="color: #6b7280; font-size: 12px; margin-top: 20px;">Submitted via ContractSpec contact form</p>
|
|
465
|
+
</div>
|
|
466
|
+
`;
|
|
467
|
+
const sendResult = await sendEmail(configResult.config, {
|
|
468
|
+
to: [configResult.config.teamInbox],
|
|
469
|
+
subject: `New Contact Form Message from ${senderName}`,
|
|
470
|
+
text: emailContentText,
|
|
471
|
+
html: emailContentHtml,
|
|
472
|
+
replyTo: email,
|
|
473
|
+
context: "contact-form"
|
|
474
|
+
});
|
|
475
|
+
if (!sendResult.success) {
|
|
476
|
+
return { success: false, text: CONTACT_SEND_ERROR };
|
|
477
|
+
}
|
|
478
|
+
return { success: true, text: "Message sent successfully!" };
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
// src/components/marketing/studio-signup-section.tsx
|
|
482
|
+
import { ArrowRight, Sparkles } from "lucide-react";
|
|
483
|
+
import Link2 from "next/link";
|
|
484
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
485
|
+
"use client";
|
|
486
|
+
var studioUrl = "https://www.contractspec.studio";
|
|
487
|
+
var studioDocsUrl = "https://www.contractspec.studio/docs";
|
|
488
|
+
function StudioSignupSection({
|
|
489
|
+
variant = "default"
|
|
490
|
+
}) {
|
|
491
|
+
const isCompact = variant === "compact";
|
|
492
|
+
return /* @__PURE__ */ jsxDEV3("div", {
|
|
493
|
+
id: "studio-signup",
|
|
494
|
+
className: `${isCompact ? "space-y-5 rounded-[28px] border border-border bg-card p-6" : "editorial-panel space-y-6"}`,
|
|
495
|
+
children: [
|
|
496
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
497
|
+
className: "space-y-4",
|
|
498
|
+
children: [
|
|
499
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
500
|
+
className: "badge",
|
|
501
|
+
children: [
|
|
502
|
+
/* @__PURE__ */ jsxDEV3(Sparkles, {
|
|
503
|
+
size: 14
|
|
504
|
+
}, undefined, false, undefined, this),
|
|
505
|
+
"Studio on top"
|
|
506
|
+
]
|
|
507
|
+
}, undefined, true, undefined, this),
|
|
508
|
+
/* @__PURE__ */ jsxDEV3("h2", {
|
|
509
|
+
className: isCompact ? "font-serif text-3xl tracking-[-0.04em]" : "font-serif text-4xl tracking-[-0.04em]",
|
|
510
|
+
children: "See the operating layer built on top of the open system."
|
|
511
|
+
}, undefined, false, undefined, this),
|
|
512
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
513
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
514
|
+
children: "Studio packages the workflow for evidence, drafting, review, export, and follow-up. It should feel like the best product built on top of ContractSpec, not a different story."
|
|
515
|
+
}, undefined, false, undefined, this)
|
|
516
|
+
]
|
|
517
|
+
}, undefined, true, undefined, this),
|
|
518
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
519
|
+
className: "grid gap-3 sm:grid-cols-2",
|
|
520
|
+
children: [
|
|
521
|
+
/* @__PURE__ */ jsxDEV3(Link2, {
|
|
522
|
+
href: studioUrl,
|
|
523
|
+
className: "btn-primary",
|
|
524
|
+
children: [
|
|
525
|
+
"Explore Studio ",
|
|
526
|
+
/* @__PURE__ */ jsxDEV3(ArrowRight, {
|
|
527
|
+
className: "ml-2 h-4 w-4"
|
|
528
|
+
}, undefined, false, undefined, this)
|
|
529
|
+
]
|
|
530
|
+
}, undefined, true, undefined, this),
|
|
531
|
+
/* @__PURE__ */ jsxDEV3(Link2, {
|
|
532
|
+
href: studioDocsUrl,
|
|
533
|
+
className: "btn-ghost",
|
|
534
|
+
children: "Read Studio docs"
|
|
535
|
+
}, undefined, false, undefined, this)
|
|
536
|
+
]
|
|
537
|
+
}, undefined, true, undefined, this)
|
|
538
|
+
]
|
|
539
|
+
}, undefined, true, undefined, this);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// src/components/marketing/ContactClient.tsx
|
|
543
|
+
import {
|
|
544
|
+
ActionForm,
|
|
545
|
+
Button,
|
|
546
|
+
Input,
|
|
547
|
+
Textarea
|
|
548
|
+
} from "@contractspec/lib.design-system";
|
|
549
|
+
import {
|
|
550
|
+
AlertCircle,
|
|
551
|
+
Calendar,
|
|
552
|
+
CheckCircle,
|
|
553
|
+
MessageSquare
|
|
554
|
+
} from "lucide-react";
|
|
555
|
+
import { useActionState } from "react";
|
|
556
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
557
|
+
"use client";
|
|
558
|
+
function ContactClient() {
|
|
559
|
+
const handleContactSubmit = async (_prevState, formData) => {
|
|
560
|
+
const result = await submitContactForm(formData);
|
|
561
|
+
if (result.success) {
|
|
562
|
+
return {
|
|
563
|
+
success: true,
|
|
564
|
+
text: "Message sent successfully. We'll get back to you soon."
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
success: false,
|
|
569
|
+
text: result.text || "Failed to send message. Please try again."
|
|
570
|
+
};
|
|
571
|
+
};
|
|
572
|
+
const [contactResult, contactAction, contactPending] = useActionState(handleContactSubmit, null);
|
|
573
|
+
return /* @__PURE__ */ jsxDEV4("main", {
|
|
574
|
+
children: [
|
|
575
|
+
/* @__PURE__ */ jsxDEV4("section", {
|
|
576
|
+
className: "section-padding hero-gradient border-border/70 border-b",
|
|
577
|
+
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
578
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[1.05fr_0.95fr]",
|
|
579
|
+
children: [
|
|
580
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
581
|
+
className: "space-y-5",
|
|
582
|
+
children: [
|
|
583
|
+
/* @__PURE__ */ jsxDEV4("p", {
|
|
584
|
+
className: "editorial-kicker",
|
|
585
|
+
children: "Contact"
|
|
586
|
+
}, undefined, false, undefined, this),
|
|
587
|
+
/* @__PURE__ */ jsxDEV4("h1", {
|
|
588
|
+
className: "editorial-title max-w-4xl",
|
|
589
|
+
children: "Talk to the team behind the open system and the Studio product."
|
|
590
|
+
}, undefined, false, undefined, this),
|
|
591
|
+
/* @__PURE__ */ jsxDEV4("p", {
|
|
592
|
+
className: "editorial-subtitle",
|
|
593
|
+
children: "Reach out when you are evaluating the OSS foundation, deciding whether Studio fits your workflow, or want a direct conversation about adoption."
|
|
594
|
+
}, undefined, false, undefined, this)
|
|
595
|
+
]
|
|
596
|
+
}, undefined, true, undefined, this),
|
|
597
|
+
/* @__PURE__ */ jsxDEV4(StudioSignupSection, {
|
|
598
|
+
variant: "compact"
|
|
599
|
+
}, undefined, false, undefined, this)
|
|
600
|
+
]
|
|
601
|
+
}, undefined, true, undefined, this)
|
|
602
|
+
}, undefined, false, undefined, this),
|
|
603
|
+
/* @__PURE__ */ jsxDEV4("section", {
|
|
604
|
+
className: "editorial-section",
|
|
605
|
+
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
606
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-2",
|
|
607
|
+
children: [
|
|
608
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
609
|
+
className: "editorial-panel space-y-6",
|
|
610
|
+
id: "call",
|
|
611
|
+
children: [
|
|
612
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
613
|
+
className: "space-y-3",
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
616
|
+
className: "badge",
|
|
617
|
+
children: [
|
|
618
|
+
/* @__PURE__ */ jsxDEV4(Calendar, {
|
|
619
|
+
size: 14
|
|
620
|
+
}, undefined, false, undefined, this),
|
|
621
|
+
"Book a conversation"
|
|
622
|
+
]
|
|
623
|
+
}, undefined, true, undefined, this),
|
|
624
|
+
/* @__PURE__ */ jsxDEV4("h2", {
|
|
625
|
+
className: "font-serif text-4xl tracking-[-0.04em]",
|
|
626
|
+
children: "Walk through your current system with us."
|
|
627
|
+
}, undefined, false, undefined, this),
|
|
628
|
+
/* @__PURE__ */ jsxDEV4("p", {
|
|
629
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
630
|
+
children: "Use the call when you want a direct conversation about fit, adoption order, or the right entry point between OSS and Studio."
|
|
631
|
+
}, undefined, false, undefined, this)
|
|
632
|
+
]
|
|
633
|
+
}, undefined, true, undefined, this),
|
|
634
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
635
|
+
className: "overflow-hidden rounded-[28px] border border-border",
|
|
636
|
+
children: /* @__PURE__ */ jsxDEV4("object", {
|
|
637
|
+
data: "https://meet.reclaimai.com/e/f863cb29-caac-44b6-972b-1407dd9545a3",
|
|
638
|
+
width: "100%",
|
|
639
|
+
height: "700px",
|
|
640
|
+
style: { outline: "none" },
|
|
641
|
+
"aria-label": "Calendar booking widget"
|
|
642
|
+
}, undefined, false, undefined, this)
|
|
643
|
+
}, undefined, false, undefined, this)
|
|
644
|
+
]
|
|
645
|
+
}, undefined, true, undefined, this),
|
|
646
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
647
|
+
className: "editorial-panel space-y-6",
|
|
648
|
+
id: "message",
|
|
649
|
+
children: [
|
|
650
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
651
|
+
className: "space-y-3",
|
|
652
|
+
children: [
|
|
653
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
654
|
+
className: "badge",
|
|
655
|
+
children: [
|
|
656
|
+
/* @__PURE__ */ jsxDEV4(MessageSquare, {
|
|
657
|
+
size: 14
|
|
658
|
+
}, undefined, false, undefined, this),
|
|
659
|
+
"Send a message"
|
|
660
|
+
]
|
|
661
|
+
}, undefined, true, undefined, this),
|
|
662
|
+
/* @__PURE__ */ jsxDEV4("h2", {
|
|
663
|
+
className: "font-serif text-4xl tracking-[-0.04em]",
|
|
664
|
+
children: "Share context, questions, or a project we should understand."
|
|
665
|
+
}, undefined, false, undefined, this)
|
|
666
|
+
]
|
|
667
|
+
}, undefined, true, undefined, this),
|
|
668
|
+
/* @__PURE__ */ jsxDEV4(ActionForm, {
|
|
669
|
+
action: contactAction,
|
|
670
|
+
children: /* @__PURE__ */ jsxDEV4("div", {
|
|
671
|
+
className: "space-y-4",
|
|
672
|
+
children: [
|
|
673
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
674
|
+
className: "space-y-2",
|
|
675
|
+
children: [
|
|
676
|
+
/* @__PURE__ */ jsxDEV4("label", {
|
|
677
|
+
htmlFor: "contact-name",
|
|
678
|
+
className: "font-medium text-sm",
|
|
679
|
+
children: "Name"
|
|
680
|
+
}, undefined, false, undefined, this),
|
|
681
|
+
/* @__PURE__ */ jsxDEV4(Input, {
|
|
682
|
+
id: "contact-name",
|
|
683
|
+
name: "name",
|
|
684
|
+
type: "text",
|
|
685
|
+
placeholder: "Your name",
|
|
686
|
+
disabled: contactPending || contactResult?.success,
|
|
687
|
+
required: true
|
|
688
|
+
}, undefined, false, undefined, this)
|
|
689
|
+
]
|
|
690
|
+
}, undefined, true, undefined, this),
|
|
691
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
692
|
+
className: "space-y-2",
|
|
693
|
+
children: [
|
|
694
|
+
/* @__PURE__ */ jsxDEV4("label", {
|
|
695
|
+
htmlFor: "contact-email",
|
|
696
|
+
className: "font-medium text-sm",
|
|
697
|
+
children: "Email"
|
|
698
|
+
}, undefined, false, undefined, this),
|
|
699
|
+
/* @__PURE__ */ jsxDEV4(Input, {
|
|
700
|
+
id: "contact-email",
|
|
701
|
+
name: "email",
|
|
702
|
+
type: "email",
|
|
703
|
+
keyboard: { kind: "email" },
|
|
704
|
+
placeholder: "you@company.com",
|
|
705
|
+
disabled: contactPending || contactResult?.success,
|
|
706
|
+
required: true
|
|
707
|
+
}, undefined, false, undefined, this)
|
|
708
|
+
]
|
|
709
|
+
}, undefined, true, undefined, this),
|
|
710
|
+
/* @__PURE__ */ jsxDEV4("div", {
|
|
711
|
+
className: "space-y-2",
|
|
712
|
+
children: [
|
|
713
|
+
/* @__PURE__ */ jsxDEV4("label", {
|
|
714
|
+
htmlFor: "contact-message",
|
|
715
|
+
className: "font-medium text-sm",
|
|
716
|
+
children: "Message"
|
|
717
|
+
}, undefined, false, undefined, this),
|
|
718
|
+
/* @__PURE__ */ jsxDEV4(Textarea, {
|
|
719
|
+
id: "contact-message",
|
|
720
|
+
name: "message",
|
|
721
|
+
placeholder: "What are you trying to stabilize, and where is the current system breaking down?",
|
|
722
|
+
disabled: contactPending || contactResult?.success,
|
|
723
|
+
rows: 7,
|
|
724
|
+
required: true
|
|
725
|
+
}, undefined, false, undefined, this)
|
|
726
|
+
]
|
|
727
|
+
}, undefined, true, undefined, this),
|
|
728
|
+
contactResult && !contactPending ? /* @__PURE__ */ jsxDEV4("div", {
|
|
729
|
+
className: `flex items-center gap-2 rounded-2xl border px-4 py-3 text-sm ${contactResult.success ? "border-green-600/20 bg-green-600/10 text-green-700" : "border-red-600/20 bg-red-600/10 text-red-700"}`,
|
|
730
|
+
children: [
|
|
731
|
+
contactResult.success ? /* @__PURE__ */ jsxDEV4(CheckCircle, {
|
|
732
|
+
size: 16
|
|
733
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV4(AlertCircle, {
|
|
734
|
+
size: 16
|
|
735
|
+
}, undefined, false, undefined, this),
|
|
736
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
737
|
+
children: contactResult.text
|
|
738
|
+
}, undefined, false, undefined, this)
|
|
739
|
+
]
|
|
740
|
+
}, undefined, true, undefined, this) : null,
|
|
741
|
+
/* @__PURE__ */ jsxDEV4(Button, {
|
|
742
|
+
type: "submit",
|
|
743
|
+
disabled: contactPending || contactResult?.success,
|
|
744
|
+
className: "w-full",
|
|
745
|
+
children: contactPending ? "Sending..." : "Send message"
|
|
746
|
+
}, undefined, false, undefined, this)
|
|
747
|
+
]
|
|
748
|
+
}, undefined, true, undefined, this)
|
|
749
|
+
}, undefined, false, undefined, this)
|
|
750
|
+
]
|
|
751
|
+
}, undefined, true, undefined, this)
|
|
752
|
+
]
|
|
753
|
+
}, undefined, true, undefined, this)
|
|
754
|
+
}, undefined, false, undefined, this)
|
|
755
|
+
]
|
|
756
|
+
}, undefined, true, undefined, this);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// src/components/marketing/ContributePage.tsx
|
|
760
|
+
import Link3 from "next/link";
|
|
761
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
762
|
+
var contributionTracks = [
|
|
763
|
+
{
|
|
764
|
+
title: "Contracts and runtime behavior",
|
|
765
|
+
copy: "Improve the core system surfaces that keep APIs, UI, data, and tools aligned."
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
title: "Examples and templates",
|
|
769
|
+
copy: "Show how the open system behaves in realistic verticals and team workflows."
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
title: "Docs and agent-facing guidance",
|
|
773
|
+
copy: "Tighten the human and machine-readable guides that explain how the stack actually works."
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
title: "Integrations and ecosystem",
|
|
777
|
+
copy: "Expand the bridges that make the system usable in more real-world environments."
|
|
778
|
+
}
|
|
779
|
+
];
|
|
780
|
+
function ContributePage() {
|
|
781
|
+
return /* @__PURE__ */ jsxDEV5("main", {
|
|
782
|
+
children: [
|
|
783
|
+
/* @__PURE__ */ jsxDEV5("section", {
|
|
784
|
+
className: "section-padding hero-gradient border-border/70 border-b",
|
|
785
|
+
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
786
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[1.05fr_0.95fr]",
|
|
787
|
+
children: [
|
|
788
|
+
/* @__PURE__ */ jsxDEV5("div", {
|
|
789
|
+
className: "space-y-5",
|
|
790
|
+
children: [
|
|
791
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
792
|
+
className: "editorial-kicker",
|
|
793
|
+
children: "Open source"
|
|
794
|
+
}, undefined, false, undefined, this),
|
|
795
|
+
/* @__PURE__ */ jsxDEV5("h1", {
|
|
796
|
+
className: "editorial-title max-w-4xl",
|
|
797
|
+
children: "Contribute to the open system, not a black box."
|
|
798
|
+
}, undefined, false, undefined, this),
|
|
799
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
800
|
+
className: "editorial-subtitle",
|
|
801
|
+
children: "ContractSpec should stay legible, standards-first, and useful in real workflows. Contributions matter most when they sharpen that clarity instead of adding abstraction for its own sake."
|
|
802
|
+
}, undefined, false, undefined, this)
|
|
803
|
+
]
|
|
804
|
+
}, undefined, true, undefined, this),
|
|
805
|
+
/* @__PURE__ */ jsxDEV5("div", {
|
|
806
|
+
className: "editorial-panel space-y-5",
|
|
807
|
+
children: [
|
|
808
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
809
|
+
className: "editorial-kicker",
|
|
810
|
+
children: "Fastest path"
|
|
811
|
+
}, undefined, false, undefined, this),
|
|
812
|
+
/* @__PURE__ */ jsxDEV5("ol", {
|
|
813
|
+
className: "space-y-4 text-muted-foreground text-sm leading-7",
|
|
814
|
+
children: [
|
|
815
|
+
/* @__PURE__ */ jsxDEV5("li", {
|
|
816
|
+
children: "Read the contribution guide and pick a tractable scope."
|
|
817
|
+
}, undefined, false, undefined, this),
|
|
818
|
+
/* @__PURE__ */ jsxDEV5("li", {
|
|
819
|
+
children: "Open a draft PR early so maintainers can steer the work."
|
|
820
|
+
}, undefined, false, undefined, this),
|
|
821
|
+
/* @__PURE__ */ jsxDEV5("li", {
|
|
822
|
+
children: "Ship one clear improvement with tests or validation evidence."
|
|
823
|
+
}, undefined, false, undefined, this)
|
|
824
|
+
]
|
|
825
|
+
}, undefined, true, undefined, this),
|
|
826
|
+
/* @__PURE__ */ jsxDEV5("div", {
|
|
827
|
+
className: "flex flex-col gap-3 sm:flex-row",
|
|
828
|
+
children: [
|
|
829
|
+
/* @__PURE__ */ jsxDEV5(Link3, {
|
|
830
|
+
href: "https://github.com/lssm-tech/contractspec/blob/main/CONTRIBUTING.md",
|
|
831
|
+
className: "btn-primary",
|
|
832
|
+
target: "_blank",
|
|
833
|
+
rel: "noopener noreferrer",
|
|
834
|
+
children: "Read CONTRIBUTING"
|
|
835
|
+
}, undefined, false, undefined, this),
|
|
836
|
+
/* @__PURE__ */ jsxDEV5(Link3, {
|
|
837
|
+
href: "https://github.com/lssm-tech/contractspec/issues",
|
|
838
|
+
className: "btn-ghost",
|
|
839
|
+
target: "_blank",
|
|
840
|
+
rel: "noopener noreferrer",
|
|
841
|
+
children: "Open issues"
|
|
842
|
+
}, undefined, false, undefined, this)
|
|
843
|
+
]
|
|
844
|
+
}, undefined, true, undefined, this)
|
|
845
|
+
]
|
|
846
|
+
}, undefined, true, undefined, this)
|
|
847
|
+
]
|
|
848
|
+
}, undefined, true, undefined, this)
|
|
849
|
+
}, undefined, false, undefined, this),
|
|
850
|
+
/* @__PURE__ */ jsxDEV5("section", {
|
|
851
|
+
className: "editorial-section",
|
|
852
|
+
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
853
|
+
className: "editorial-shell space-y-8",
|
|
854
|
+
children: [
|
|
855
|
+
/* @__PURE__ */ jsxDEV5("div", {
|
|
856
|
+
className: "max-w-3xl space-y-4",
|
|
857
|
+
children: [
|
|
858
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
859
|
+
className: "editorial-kicker",
|
|
860
|
+
children: "Where contributions matter most"
|
|
861
|
+
}, undefined, false, undefined, this),
|
|
862
|
+
/* @__PURE__ */ jsxDEV5("h2", {
|
|
863
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
864
|
+
children: "Work on the parts that make the system clearer and safer."
|
|
865
|
+
}, undefined, false, undefined, this)
|
|
866
|
+
]
|
|
867
|
+
}, undefined, true, undefined, this),
|
|
868
|
+
/* @__PURE__ */ jsxDEV5("div", {
|
|
869
|
+
className: "editorial-grid",
|
|
870
|
+
children: contributionTracks.map((track) => /* @__PURE__ */ jsxDEV5("div", {
|
|
871
|
+
className: "editorial-panel",
|
|
872
|
+
children: [
|
|
873
|
+
/* @__PURE__ */ jsxDEV5("h3", {
|
|
874
|
+
className: "font-serif text-2xl tracking-[-0.03em]",
|
|
875
|
+
children: track.title
|
|
876
|
+
}, undefined, false, undefined, this),
|
|
877
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
878
|
+
className: "mt-3 text-muted-foreground text-sm leading-7",
|
|
879
|
+
children: track.copy
|
|
880
|
+
}, undefined, false, undefined, this)
|
|
881
|
+
]
|
|
882
|
+
}, track.title, true, undefined, this))
|
|
883
|
+
}, undefined, false, undefined, this)
|
|
884
|
+
]
|
|
885
|
+
}, undefined, true, undefined, this)
|
|
886
|
+
}, undefined, false, undefined, this),
|
|
887
|
+
/* @__PURE__ */ jsxDEV5("section", {
|
|
888
|
+
className: "editorial-section bg-striped",
|
|
889
|
+
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
890
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-2",
|
|
891
|
+
children: [
|
|
892
|
+
/* @__PURE__ */ jsxDEV5("div", {
|
|
893
|
+
className: "editorial-panel",
|
|
894
|
+
children: [
|
|
895
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
896
|
+
className: "editorial-kicker",
|
|
897
|
+
children: "Quality bar"
|
|
898
|
+
}, undefined, false, undefined, this),
|
|
899
|
+
/* @__PURE__ */ jsxDEV5("h2", {
|
|
900
|
+
className: "font-serif text-4xl tracking-[-0.04em]",
|
|
901
|
+
children: "The contribution should make the repo easier to trust."
|
|
902
|
+
}, undefined, false, undefined, this),
|
|
903
|
+
/* @__PURE__ */ jsxDEV5("ul", {
|
|
904
|
+
className: "editorial-list mt-6",
|
|
905
|
+
children: [
|
|
906
|
+
/* @__PURE__ */ jsxDEV5("li", {
|
|
907
|
+
children: [
|
|
908
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
909
|
+
className: "editorial-list-marker"
|
|
910
|
+
}, undefined, false, undefined, this),
|
|
911
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
912
|
+
children: "Use strict TypeScript and keep changes explicit."
|
|
913
|
+
}, undefined, false, undefined, this)
|
|
914
|
+
]
|
|
915
|
+
}, undefined, true, undefined, this),
|
|
916
|
+
/* @__PURE__ */ jsxDEV5("li", {
|
|
917
|
+
children: [
|
|
918
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
919
|
+
className: "editorial-list-marker"
|
|
920
|
+
}, undefined, false, undefined, this),
|
|
921
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
922
|
+
children: "Include tests or other concrete validation where behavior changes."
|
|
923
|
+
}, undefined, false, undefined, this)
|
|
924
|
+
]
|
|
925
|
+
}, undefined, true, undefined, this),
|
|
926
|
+
/* @__PURE__ */ jsxDEV5("li", {
|
|
927
|
+
children: [
|
|
928
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
929
|
+
className: "editorial-list-marker"
|
|
930
|
+
}, undefined, false, undefined, this),
|
|
931
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
932
|
+
children: "Prefer one coherent concern per PR."
|
|
933
|
+
}, undefined, false, undefined, this)
|
|
934
|
+
]
|
|
935
|
+
}, undefined, true, undefined, this),
|
|
936
|
+
/* @__PURE__ */ jsxDEV5("li", {
|
|
937
|
+
children: [
|
|
938
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
939
|
+
className: "editorial-list-marker"
|
|
940
|
+
}, undefined, false, undefined, this),
|
|
941
|
+
/* @__PURE__ */ jsxDEV5("span", {
|
|
942
|
+
children: "Document the public or agent-facing impact when it exists."
|
|
943
|
+
}, undefined, false, undefined, this)
|
|
944
|
+
]
|
|
945
|
+
}, undefined, true, undefined, this)
|
|
946
|
+
]
|
|
947
|
+
}, undefined, true, undefined, this)
|
|
948
|
+
]
|
|
949
|
+
}, undefined, true, undefined, this),
|
|
950
|
+
/* @__PURE__ */ jsxDEV5("div", {
|
|
951
|
+
className: "editorial-panel",
|
|
952
|
+
children: [
|
|
953
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
954
|
+
className: "editorial-kicker",
|
|
955
|
+
children: "Governance and security"
|
|
956
|
+
}, undefined, false, undefined, this),
|
|
957
|
+
/* @__PURE__ */ jsxDEV5("h2", {
|
|
958
|
+
className: "font-serif text-4xl tracking-[-0.04em]",
|
|
959
|
+
children: "Clarity first, private disclosure when the issue is sensitive."
|
|
960
|
+
}, undefined, false, undefined, this),
|
|
961
|
+
/* @__PURE__ */ jsxDEV5("p", {
|
|
962
|
+
className: "mt-5 text-muted-foreground text-sm leading-7",
|
|
963
|
+
children: [
|
|
964
|
+
"Architecture and roadmap decisions stay founder-led for now, but the reasoning should stay inspectable in issues, PRs, and docs. If you find a security issue, do not open a public ticket. Use",
|
|
965
|
+
" ",
|
|
966
|
+
/* @__PURE__ */ jsxDEV5(Link3, {
|
|
967
|
+
href: "mailto:security@contractspec.io",
|
|
968
|
+
className: "underline",
|
|
969
|
+
children: "security@contractspec.io"
|
|
970
|
+
}, undefined, false, undefined, this),
|
|
971
|
+
" ",
|
|
972
|
+
"instead."
|
|
973
|
+
]
|
|
974
|
+
}, undefined, true, undefined, this)
|
|
975
|
+
]
|
|
976
|
+
}, undefined, true, undefined, this)
|
|
977
|
+
]
|
|
978
|
+
}, undefined, true, undefined, this)
|
|
979
|
+
}, undefined, false, undefined, this)
|
|
980
|
+
]
|
|
981
|
+
}, undefined, true, undefined, this);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// src/components/marketing/DesignPartnerPage.tsx
|
|
985
|
+
import Link4 from "next/link";
|
|
986
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
987
|
+
var metadata = {
|
|
988
|
+
title: "Design Partner | ContractSpec",
|
|
989
|
+
description: "Work directly with the ContractSpec team if you are shaping a live AI-native product or operations workflow."
|
|
990
|
+
};
|
|
991
|
+
var steps = [
|
|
992
|
+
{
|
|
993
|
+
title: "Run the open system against a live problem",
|
|
994
|
+
copy: "Bring one workflow or module that already feels risky, inconsistent, or hard to regenerate safely."
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
title: "Use Studio where packaged coordination helps",
|
|
998
|
+
copy: "We focus on the parts of your loop where an operating product materially reduces friction for the team."
|
|
999
|
+
},
|
|
1000
|
+
{
|
|
1001
|
+
title: "Feed real constraints back into the product",
|
|
1002
|
+
copy: "The partnership is valuable when your live complexity changes what we should build next."
|
|
1003
|
+
}
|
|
1004
|
+
];
|
|
1005
|
+
function DesignPartnerPage() {
|
|
1006
|
+
return /* @__PURE__ */ jsxDEV6("main", {
|
|
1007
|
+
children: [
|
|
1008
|
+
/* @__PURE__ */ jsxDEV6("section", {
|
|
1009
|
+
className: "section-padding hero-gradient border-border/70 border-b",
|
|
1010
|
+
children: /* @__PURE__ */ jsxDEV6("div", {
|
|
1011
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[1.05fr_0.95fr]",
|
|
1012
|
+
children: [
|
|
1013
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1014
|
+
className: "space-y-5",
|
|
1015
|
+
children: [
|
|
1016
|
+
/* @__PURE__ */ jsxDEV6("p", {
|
|
1017
|
+
className: "editorial-kicker",
|
|
1018
|
+
children: "Design partner program"
|
|
1019
|
+
}, undefined, false, undefined, this),
|
|
1020
|
+
/* @__PURE__ */ jsxDEV6("h1", {
|
|
1021
|
+
className: "editorial-title max-w-4xl",
|
|
1022
|
+
children: "Shape the operating product from real AI-native workflow pressure."
|
|
1023
|
+
}, undefined, false, undefined, this),
|
|
1024
|
+
/* @__PURE__ */ jsxDEV6("p", {
|
|
1025
|
+
className: "editorial-subtitle",
|
|
1026
|
+
children: "The design partner path is for teams whose complexity is already real: multiple surfaces, live signals, coordination cost, and unsafe regeneration pain. We use that pressure to sharpen both the open foundation and the Studio layer on top."
|
|
1027
|
+
}, undefined, false, undefined, this)
|
|
1028
|
+
]
|
|
1029
|
+
}, undefined, true, undefined, this),
|
|
1030
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1031
|
+
className: "editorial-panel space-y-5",
|
|
1032
|
+
children: [
|
|
1033
|
+
/* @__PURE__ */ jsxDEV6("p", {
|
|
1034
|
+
className: "editorial-kicker",
|
|
1035
|
+
children: "Who this is for"
|
|
1036
|
+
}, undefined, false, undefined, this),
|
|
1037
|
+
/* @__PURE__ */ jsxDEV6("ul", {
|
|
1038
|
+
className: "editorial-list",
|
|
1039
|
+
children: [
|
|
1040
|
+
/* @__PURE__ */ jsxDEV6("li", {
|
|
1041
|
+
children: [
|
|
1042
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1043
|
+
className: "editorial-list-marker"
|
|
1044
|
+
}, undefined, false, undefined, this),
|
|
1045
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1046
|
+
children: "Small teams already shipping AI-assisted products or ops loops."
|
|
1047
|
+
}, undefined, false, undefined, this)
|
|
1048
|
+
]
|
|
1049
|
+
}, undefined, true, undefined, this),
|
|
1050
|
+
/* @__PURE__ */ jsxDEV6("li", {
|
|
1051
|
+
children: [
|
|
1052
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1053
|
+
className: "editorial-list-marker"
|
|
1054
|
+
}, undefined, false, undefined, this),
|
|
1055
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1056
|
+
children: "Builders who want direct access to the product team."
|
|
1057
|
+
}, undefined, false, undefined, this)
|
|
1058
|
+
]
|
|
1059
|
+
}, undefined, true, undefined, this),
|
|
1060
|
+
/* @__PURE__ */ jsxDEV6("li", {
|
|
1061
|
+
children: [
|
|
1062
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1063
|
+
className: "editorial-list-marker"
|
|
1064
|
+
}, undefined, false, undefined, this),
|
|
1065
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1066
|
+
children: "Teams comfortable shaping a product in motion."
|
|
1067
|
+
}, undefined, false, undefined, this)
|
|
1068
|
+
]
|
|
1069
|
+
}, undefined, true, undefined, this)
|
|
1070
|
+
]
|
|
1071
|
+
}, undefined, true, undefined, this),
|
|
1072
|
+
/* @__PURE__ */ jsxDEV6(Link4, {
|
|
1073
|
+
href: "mailto:partners@contractspec.io",
|
|
1074
|
+
className: "btn-primary",
|
|
1075
|
+
children: "Contact partner team"
|
|
1076
|
+
}, undefined, false, undefined, this)
|
|
1077
|
+
]
|
|
1078
|
+
}, undefined, true, undefined, this)
|
|
1079
|
+
]
|
|
1080
|
+
}, undefined, true, undefined, this)
|
|
1081
|
+
}, undefined, false, undefined, this),
|
|
1082
|
+
/* @__PURE__ */ jsxDEV6("section", {
|
|
1083
|
+
className: "editorial-section",
|
|
1084
|
+
children: /* @__PURE__ */ jsxDEV6("div", {
|
|
1085
|
+
className: "editorial-shell grid gap-5 md:grid-cols-3",
|
|
1086
|
+
children: steps.map((step, index) => /* @__PURE__ */ jsxDEV6("div", {
|
|
1087
|
+
className: "editorial-panel space-y-4",
|
|
1088
|
+
children: [
|
|
1089
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1090
|
+
className: "flex h-9 w-9 items-center justify-center rounded-full bg-[rgb(162_79_42_/_0.12)] font-mono text-[color:var(--rust)] text-xs",
|
|
1091
|
+
children: [
|
|
1092
|
+
"0",
|
|
1093
|
+
index + 1
|
|
1094
|
+
]
|
|
1095
|
+
}, undefined, true, undefined, this),
|
|
1096
|
+
/* @__PURE__ */ jsxDEV6("h2", {
|
|
1097
|
+
className: "font-serif text-3xl tracking-[-0.04em]",
|
|
1098
|
+
children: step.title
|
|
1099
|
+
}, undefined, false, undefined, this),
|
|
1100
|
+
/* @__PURE__ */ jsxDEV6("p", {
|
|
1101
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
1102
|
+
children: step.copy
|
|
1103
|
+
}, undefined, false, undefined, this)
|
|
1104
|
+
]
|
|
1105
|
+
}, step.title, true, undefined, this))
|
|
1106
|
+
}, undefined, false, undefined, this)
|
|
1107
|
+
}, undefined, false, undefined, this),
|
|
1108
|
+
/* @__PURE__ */ jsxDEV6("section", {
|
|
1109
|
+
className: "editorial-section bg-striped",
|
|
1110
|
+
children: /* @__PURE__ */ jsxDEV6("div", {
|
|
1111
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-2",
|
|
1112
|
+
children: [
|
|
1113
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1114
|
+
className: "editorial-panel",
|
|
1115
|
+
children: [
|
|
1116
|
+
/* @__PURE__ */ jsxDEV6("p", {
|
|
1117
|
+
className: "editorial-kicker",
|
|
1118
|
+
children: "What you get"
|
|
1119
|
+
}, undefined, false, undefined, this),
|
|
1120
|
+
/* @__PURE__ */ jsxDEV6("ul", {
|
|
1121
|
+
className: "editorial-list mt-6",
|
|
1122
|
+
children: [
|
|
1123
|
+
/* @__PURE__ */ jsxDEV6("li", {
|
|
1124
|
+
children: [
|
|
1125
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1126
|
+
className: "editorial-list-marker"
|
|
1127
|
+
}, undefined, false, undefined, this),
|
|
1128
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1129
|
+
children: "Direct access to the builders instead of generic support routing."
|
|
1130
|
+
}, undefined, false, undefined, this)
|
|
1131
|
+
]
|
|
1132
|
+
}, undefined, true, undefined, this),
|
|
1133
|
+
/* @__PURE__ */ jsxDEV6("li", {
|
|
1134
|
+
children: [
|
|
1135
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1136
|
+
className: "editorial-list-marker"
|
|
1137
|
+
}, undefined, false, undefined, this),
|
|
1138
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1139
|
+
children: "Faster feedback cycles around the workflows that matter to you."
|
|
1140
|
+
}, undefined, false, undefined, this)
|
|
1141
|
+
]
|
|
1142
|
+
}, undefined, true, undefined, this),
|
|
1143
|
+
/* @__PURE__ */ jsxDEV6("li", {
|
|
1144
|
+
children: [
|
|
1145
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1146
|
+
className: "editorial-list-marker"
|
|
1147
|
+
}, undefined, false, undefined, this),
|
|
1148
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1149
|
+
children: "Input into how OSS and Studio packaging should evolve together."
|
|
1150
|
+
}, undefined, false, undefined, this)
|
|
1151
|
+
]
|
|
1152
|
+
}, undefined, true, undefined, this)
|
|
1153
|
+
]
|
|
1154
|
+
}, undefined, true, undefined, this)
|
|
1155
|
+
]
|
|
1156
|
+
}, undefined, true, undefined, this),
|
|
1157
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1158
|
+
className: "editorial-panel",
|
|
1159
|
+
children: [
|
|
1160
|
+
/* @__PURE__ */ jsxDEV6("p", {
|
|
1161
|
+
className: "editorial-kicker",
|
|
1162
|
+
children: "How to start"
|
|
1163
|
+
}, undefined, false, undefined, this),
|
|
1164
|
+
/* @__PURE__ */ jsxDEV6("p", {
|
|
1165
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
1166
|
+
children: "Bring one concrete workflow, the current points of drift or instability, and the team context around it. That is enough to tell whether the right next step is open-system adoption, a Studio pilot, or a deeper partnership."
|
|
1167
|
+
}, undefined, false, undefined, this),
|
|
1168
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1169
|
+
className: "mt-6 flex flex-col gap-3 sm:flex-row",
|
|
1170
|
+
children: [
|
|
1171
|
+
/* @__PURE__ */ jsxDEV6(Link4, {
|
|
1172
|
+
href: "https://www.contractspec.studio",
|
|
1173
|
+
className: "btn-primary",
|
|
1174
|
+
children: "Explore Studio"
|
|
1175
|
+
}, undefined, false, undefined, this),
|
|
1176
|
+
/* @__PURE__ */ jsxDEV6(Link4, {
|
|
1177
|
+
href: "/contact",
|
|
1178
|
+
className: "btn-ghost",
|
|
1179
|
+
children: "Book a conversation"
|
|
1180
|
+
}, undefined, false, undefined, this)
|
|
1181
|
+
]
|
|
1182
|
+
}, undefined, true, undefined, this)
|
|
1183
|
+
]
|
|
1184
|
+
}, undefined, true, undefined, this)
|
|
1185
|
+
]
|
|
1186
|
+
}, undefined, true, undefined, this)
|
|
1187
|
+
}, undefined, false, undefined, this)
|
|
1188
|
+
]
|
|
1189
|
+
}, undefined, true, undefined, this);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/components/marketing/LandingPage.tsx
|
|
1193
|
+
import {
|
|
1194
|
+
ArrowRight as ArrowRight2,
|
|
1195
|
+
Blocks,
|
|
1196
|
+
Bot,
|
|
1197
|
+
Braces,
|
|
1198
|
+
ChartColumn,
|
|
1199
|
+
Database,
|
|
1200
|
+
GitBranch,
|
|
1201
|
+
ShieldCheck,
|
|
1202
|
+
Sparkles as Sparkles2,
|
|
1203
|
+
Workflow
|
|
1204
|
+
} from "lucide-react";
|
|
1205
|
+
import Link5 from "next/link";
|
|
1206
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
1207
|
+
"use client";
|
|
1208
|
+
var failureModes = [
|
|
1209
|
+
{
|
|
1210
|
+
title: "Implicit rules drift first",
|
|
1211
|
+
description: "Prompt chains and AI edits move faster than the product rules they are supposed to respect."
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
title: "Surfaces stop agreeing",
|
|
1215
|
+
description: "API, UI, database, events, and MCP tools evolve independently unless something explicit keeps them aligned."
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
title: "Teams lose safe regeneration",
|
|
1219
|
+
description: "Without a stable contract layer, every regeneration feels like rewriting production in the dark."
|
|
1220
|
+
}
|
|
1221
|
+
];
|
|
1222
|
+
var systemSurfaces = [
|
|
1223
|
+
{
|
|
1224
|
+
label: "Contracts and generation",
|
|
1225
|
+
description: "Define the canonical behavior once and derive the implementation surfaces from it.",
|
|
1226
|
+
icon: Braces
|
|
1227
|
+
},
|
|
1228
|
+
{
|
|
1229
|
+
label: "Runtime adapters",
|
|
1230
|
+
description: "Bind the same source of truth to REST, GraphQL, React, MCP, and operational flows.",
|
|
1231
|
+
icon: Workflow
|
|
1232
|
+
},
|
|
1233
|
+
{
|
|
1234
|
+
label: "Harness and proof",
|
|
1235
|
+
description: "Replay, evaluate, inspect, and verify how the system behaves before you trust automation with more.",
|
|
1236
|
+
icon: ChartColumn
|
|
1237
|
+
},
|
|
1238
|
+
{
|
|
1239
|
+
label: "Studio operating layer",
|
|
1240
|
+
description: "Run the opinionated product loop when you want coordination, governance, and a packaged operating surface.",
|
|
1241
|
+
icon: Sparkles2
|
|
1242
|
+
}
|
|
1243
|
+
];
|
|
1244
|
+
var outputs = [
|
|
1245
|
+
{
|
|
1246
|
+
title: "APIs",
|
|
1247
|
+
copy: "Typed endpoints and schemas stay aligned with the same contract language the team edits.",
|
|
1248
|
+
icon: GitBranch
|
|
1249
|
+
},
|
|
1250
|
+
{
|
|
1251
|
+
title: "Data",
|
|
1252
|
+
copy: "Schema, validation, and migrations are shaped by the same product rules instead of scattered implementations.",
|
|
1253
|
+
icon: Database
|
|
1254
|
+
},
|
|
1255
|
+
{
|
|
1256
|
+
title: "Interfaces",
|
|
1257
|
+
copy: "Forms, presentations, and client types inherit the same system boundaries instead of drifting from the backend.",
|
|
1258
|
+
icon: Blocks
|
|
1259
|
+
},
|
|
1260
|
+
{
|
|
1261
|
+
title: "Agents and tools",
|
|
1262
|
+
copy: "MCP tools and agent-facing surfaces are generated from explicit contracts rather than guessed from code.",
|
|
1263
|
+
icon: Bot
|
|
1264
|
+
}
|
|
1265
|
+
];
|
|
1266
|
+
var adoptionSteps = [
|
|
1267
|
+
"Start with one module that is already drifting or feels unsafe to regenerate.",
|
|
1268
|
+
"Define explicit contracts, then bring API, UI, data, and tools back into alignment.",
|
|
1269
|
+
"Adopt Studio when the team wants an operating surface on top of the open system."
|
|
1270
|
+
];
|
|
1271
|
+
function LandingPage() {
|
|
1272
|
+
return /* @__PURE__ */ jsxDEV7("main", {
|
|
1273
|
+
children: [
|
|
1274
|
+
/* @__PURE__ */ jsxDEV7("section", {
|
|
1275
|
+
className: "section-padding hero-gradient border-border/70 border-b",
|
|
1276
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1277
|
+
className: "editorial-shell",
|
|
1278
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1279
|
+
className: "grid gap-10 lg:grid-cols-[1.15fr_0.85fr] lg:items-end",
|
|
1280
|
+
children: [
|
|
1281
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1282
|
+
className: "space-y-7",
|
|
1283
|
+
children: [
|
|
1284
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1285
|
+
className: "badge",
|
|
1286
|
+
children: [
|
|
1287
|
+
/* @__PURE__ */ jsxDEV7(ShieldCheck, {
|
|
1288
|
+
size: 14
|
|
1289
|
+
}, undefined, false, undefined, this),
|
|
1290
|
+
"Open system, explicit control"
|
|
1291
|
+
]
|
|
1292
|
+
}, undefined, true, undefined, this),
|
|
1293
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1294
|
+
className: "space-y-5",
|
|
1295
|
+
children: [
|
|
1296
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1297
|
+
className: "editorial-kicker",
|
|
1298
|
+
children: "ContractSpec for AI-native teams"
|
|
1299
|
+
}, undefined, false, undefined, this),
|
|
1300
|
+
/* @__PURE__ */ jsxDEV7("h1", {
|
|
1301
|
+
className: "editorial-title max-w-5xl",
|
|
1302
|
+
children: "Build and run AI-native systems on explicit contracts."
|
|
1303
|
+
}, undefined, false, undefined, this),
|
|
1304
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1305
|
+
className: "editorial-subtitle",
|
|
1306
|
+
children: "ContractSpec gives teams an open spec system for defining behavior, aligning every surface, and regenerating safely. The OSS foundation stays yours. Studio is the operating layer when you want a product on top."
|
|
1307
|
+
}, undefined, false, undefined, this)
|
|
1308
|
+
]
|
|
1309
|
+
}, undefined, true, undefined, this),
|
|
1310
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1311
|
+
className: "flex flex-col gap-3 sm:flex-row",
|
|
1312
|
+
children: [
|
|
1313
|
+
/* @__PURE__ */ jsxDEV7(Link5, {
|
|
1314
|
+
href: "/install",
|
|
1315
|
+
className: "btn-primary",
|
|
1316
|
+
children: [
|
|
1317
|
+
"Start with OSS ",
|
|
1318
|
+
/* @__PURE__ */ jsxDEV7(ArrowRight2, {
|
|
1319
|
+
className: "ml-2 h-4 w-4"
|
|
1320
|
+
}, undefined, false, undefined, this)
|
|
1321
|
+
]
|
|
1322
|
+
}, undefined, true, undefined, this),
|
|
1323
|
+
/* @__PURE__ */ jsxDEV7(Link5, {
|
|
1324
|
+
href: "https://www.contractspec.studio",
|
|
1325
|
+
className: "btn-ghost",
|
|
1326
|
+
children: "Explore Studio"
|
|
1327
|
+
}, undefined, false, undefined, this),
|
|
1328
|
+
/* @__PURE__ */ jsxDEV7(Link5, {
|
|
1329
|
+
href: "/product",
|
|
1330
|
+
className: "btn-ghost",
|
|
1331
|
+
children: "See the architecture"
|
|
1332
|
+
}, undefined, false, undefined, this)
|
|
1333
|
+
]
|
|
1334
|
+
}, undefined, true, undefined, this),
|
|
1335
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1336
|
+
className: "editorial-proof-strip",
|
|
1337
|
+
children: [
|
|
1338
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1339
|
+
className: "editorial-stat",
|
|
1340
|
+
children: [
|
|
1341
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1342
|
+
className: "editorial-stat-value",
|
|
1343
|
+
children: "1"
|
|
1344
|
+
}, undefined, false, undefined, this),
|
|
1345
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1346
|
+
className: "editorial-label",
|
|
1347
|
+
children: "explicit system source"
|
|
1348
|
+
}, undefined, false, undefined, this)
|
|
1349
|
+
]
|
|
1350
|
+
}, undefined, true, undefined, this),
|
|
1351
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1352
|
+
className: "editorial-stat",
|
|
1353
|
+
children: [
|
|
1354
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1355
|
+
className: "editorial-stat-value",
|
|
1356
|
+
children: "4+"
|
|
1357
|
+
}, undefined, false, undefined, this),
|
|
1358
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1359
|
+
className: "editorial-label",
|
|
1360
|
+
children: "aligned surface families"
|
|
1361
|
+
}, undefined, false, undefined, this)
|
|
1362
|
+
]
|
|
1363
|
+
}, undefined, true, undefined, this),
|
|
1364
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1365
|
+
className: "editorial-stat",
|
|
1366
|
+
children: [
|
|
1367
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1368
|
+
className: "editorial-stat-value",
|
|
1369
|
+
children: "0"
|
|
1370
|
+
}, undefined, false, undefined, this),
|
|
1371
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1372
|
+
className: "editorial-label",
|
|
1373
|
+
children: "required lock-in"
|
|
1374
|
+
}, undefined, false, undefined, this)
|
|
1375
|
+
]
|
|
1376
|
+
}, undefined, true, undefined, this)
|
|
1377
|
+
]
|
|
1378
|
+
}, undefined, true, undefined, this)
|
|
1379
|
+
]
|
|
1380
|
+
}, undefined, true, undefined, this),
|
|
1381
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1382
|
+
className: "editorial-panel space-y-6",
|
|
1383
|
+
children: [
|
|
1384
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1385
|
+
className: "editorial-kicker",
|
|
1386
|
+
children: "What the site should make clear"
|
|
1387
|
+
}, undefined, false, undefined, this),
|
|
1388
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1389
|
+
className: "space-y-4",
|
|
1390
|
+
children: [
|
|
1391
|
+
/* @__PURE__ */ jsxDEV7("h2", {
|
|
1392
|
+
className: "editorial-panel-title",
|
|
1393
|
+
children: "This is not “yet another AI builder.”"
|
|
1394
|
+
}, undefined, false, undefined, this),
|
|
1395
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1396
|
+
className: "editorial-copy text-sm",
|
|
1397
|
+
children: "ContractSpec exists for teams that already know AI can write a lot of software, but need explicit control over what that software is allowed to become over time."
|
|
1398
|
+
}, undefined, false, undefined, this)
|
|
1399
|
+
]
|
|
1400
|
+
}, undefined, true, undefined, this),
|
|
1401
|
+
/* @__PURE__ */ jsxDEV7("ul", {
|
|
1402
|
+
className: "editorial-list",
|
|
1403
|
+
children: [
|
|
1404
|
+
/* @__PURE__ */ jsxDEV7("li", {
|
|
1405
|
+
children: [
|
|
1406
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1407
|
+
className: "editorial-list-marker"
|
|
1408
|
+
}, undefined, false, undefined, this),
|
|
1409
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1410
|
+
children: "Keep the code and the standards you already use."
|
|
1411
|
+
}, undefined, false, undefined, this)
|
|
1412
|
+
]
|
|
1413
|
+
}, undefined, true, undefined, this),
|
|
1414
|
+
/* @__PURE__ */ jsxDEV7("li", {
|
|
1415
|
+
children: [
|
|
1416
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1417
|
+
className: "editorial-list-marker"
|
|
1418
|
+
}, undefined, false, undefined, this),
|
|
1419
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1420
|
+
children: "Stabilize one module at a time instead of rewriting your app."
|
|
1421
|
+
}, undefined, false, undefined, this)
|
|
1422
|
+
]
|
|
1423
|
+
}, undefined, true, undefined, this),
|
|
1424
|
+
/* @__PURE__ */ jsxDEV7("li", {
|
|
1425
|
+
children: [
|
|
1426
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1427
|
+
className: "editorial-list-marker"
|
|
1428
|
+
}, undefined, false, undefined, this),
|
|
1429
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1430
|
+
children: "Move into Studio only when you want the operating product."
|
|
1431
|
+
}, undefined, false, undefined, this)
|
|
1432
|
+
]
|
|
1433
|
+
}, undefined, true, undefined, this)
|
|
1434
|
+
]
|
|
1435
|
+
}, undefined, true, undefined, this)
|
|
1436
|
+
]
|
|
1437
|
+
}, undefined, true, undefined, this)
|
|
1438
|
+
]
|
|
1439
|
+
}, undefined, true, undefined, this)
|
|
1440
|
+
}, undefined, false, undefined, this)
|
|
1441
|
+
}, undefined, false, undefined, this),
|
|
1442
|
+
/* @__PURE__ */ jsxDEV7("section", {
|
|
1443
|
+
className: "editorial-section",
|
|
1444
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1445
|
+
className: "editorial-shell space-y-10",
|
|
1446
|
+
children: [
|
|
1447
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1448
|
+
className: "max-w-3xl space-y-4",
|
|
1449
|
+
children: [
|
|
1450
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1451
|
+
className: "editorial-kicker",
|
|
1452
|
+
children: "Why teams end up here"
|
|
1453
|
+
}, undefined, false, undefined, this),
|
|
1454
|
+
/* @__PURE__ */ jsxDEV7("h2", {
|
|
1455
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
1456
|
+
children: "AI speed is not the problem. Implicit systems are."
|
|
1457
|
+
}, undefined, false, undefined, this),
|
|
1458
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1459
|
+
className: "editorial-copy",
|
|
1460
|
+
children: "Once a team depends on prompts, AI edits, and generated code across multiple surfaces, the real failure mode is not “AI wrote bad code.” It is that nobody can state the system rules precisely enough to keep regeneration safe."
|
|
1461
|
+
}, undefined, false, undefined, this)
|
|
1462
|
+
]
|
|
1463
|
+
}, undefined, true, undefined, this),
|
|
1464
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1465
|
+
className: "editorial-grid xl:grid-cols-3",
|
|
1466
|
+
children: failureModes.map((item) => /* @__PURE__ */ jsxDEV7("div", {
|
|
1467
|
+
className: "editorial-panel",
|
|
1468
|
+
children: [
|
|
1469
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1470
|
+
className: "editorial-kicker",
|
|
1471
|
+
children: item.title
|
|
1472
|
+
}, undefined, false, undefined, this),
|
|
1473
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1474
|
+
className: "mt-4 text-base text-muted-foreground leading-8",
|
|
1475
|
+
children: item.description
|
|
1476
|
+
}, undefined, false, undefined, this)
|
|
1477
|
+
]
|
|
1478
|
+
}, item.title, true, undefined, this))
|
|
1479
|
+
}, undefined, false, undefined, this)
|
|
1480
|
+
]
|
|
1481
|
+
}, undefined, true, undefined, this)
|
|
1482
|
+
}, undefined, false, undefined, this),
|
|
1483
|
+
/* @__PURE__ */ jsxDEV7("section", {
|
|
1484
|
+
className: "editorial-section bg-striped",
|
|
1485
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1486
|
+
className: "editorial-shell space-y-10",
|
|
1487
|
+
children: [
|
|
1488
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1489
|
+
className: "max-w-3xl space-y-4",
|
|
1490
|
+
children: [
|
|
1491
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1492
|
+
className: "editorial-kicker",
|
|
1493
|
+
children: "The open system"
|
|
1494
|
+
}, undefined, false, undefined, this),
|
|
1495
|
+
/* @__PURE__ */ jsxDEV7("h2", {
|
|
1496
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
1497
|
+
children: "One explicit layer that keeps the whole stack honest."
|
|
1498
|
+
}, undefined, false, undefined, this),
|
|
1499
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1500
|
+
className: "editorial-copy",
|
|
1501
|
+
children: "ContractSpec is broader than generation. It is the contract layer, the runtime bridges, the proof surfaces, and the adoption path that lets teams move from OSS control to an operating product without pretending they are different systems."
|
|
1502
|
+
}, undefined, false, undefined, this)
|
|
1503
|
+
]
|
|
1504
|
+
}, undefined, true, undefined, this),
|
|
1505
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1506
|
+
className: "editorial-grid",
|
|
1507
|
+
children: systemSurfaces.map((surface) => /* @__PURE__ */ jsxDEV7("div", {
|
|
1508
|
+
className: "editorial-panel",
|
|
1509
|
+
children: [
|
|
1510
|
+
/* @__PURE__ */ jsxDEV7(surface.icon, {
|
|
1511
|
+
className: "h-5 w-5 text-[color:var(--rust)]"
|
|
1512
|
+
}, undefined, false, undefined, this),
|
|
1513
|
+
/* @__PURE__ */ jsxDEV7("h3", {
|
|
1514
|
+
className: "mt-5 font-serif text-2xl tracking-[-0.03em]",
|
|
1515
|
+
children: surface.label
|
|
1516
|
+
}, undefined, false, undefined, this),
|
|
1517
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1518
|
+
className: "mt-3 text-muted-foreground text-sm leading-7",
|
|
1519
|
+
children: surface.description
|
|
1520
|
+
}, undefined, false, undefined, this)
|
|
1521
|
+
]
|
|
1522
|
+
}, surface.label, true, undefined, this))
|
|
1523
|
+
}, undefined, false, undefined, this)
|
|
1524
|
+
]
|
|
1525
|
+
}, undefined, true, undefined, this)
|
|
1526
|
+
}, undefined, false, undefined, this),
|
|
1527
|
+
/* @__PURE__ */ jsxDEV7("section", {
|
|
1528
|
+
className: "editorial-section",
|
|
1529
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1530
|
+
className: "editorial-shell grid gap-10 lg:grid-cols-[0.9fr_1.1fr]",
|
|
1531
|
+
children: [
|
|
1532
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1533
|
+
className: "space-y-4",
|
|
1534
|
+
children: [
|
|
1535
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1536
|
+
className: "editorial-kicker",
|
|
1537
|
+
children: "What the OSS layer actually gives you"
|
|
1538
|
+
}, undefined, false, undefined, this),
|
|
1539
|
+
/* @__PURE__ */ jsxDEV7("h2", {
|
|
1540
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
1541
|
+
children: "Explicit contracts show up where teams usually lose control."
|
|
1542
|
+
}, undefined, false, undefined, this),
|
|
1543
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1544
|
+
className: "editorial-copy",
|
|
1545
|
+
children: "The promise is not magic generation. The promise is that the same product rules can shape APIs, data, interfaces, and agent tools without each surface inventing its own truth."
|
|
1546
|
+
}, undefined, false, undefined, this)
|
|
1547
|
+
]
|
|
1548
|
+
}, undefined, true, undefined, this),
|
|
1549
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1550
|
+
className: "grid gap-5 md:grid-cols-2",
|
|
1551
|
+
children: outputs.map((output) => /* @__PURE__ */ jsxDEV7("div", {
|
|
1552
|
+
className: "editorial-panel",
|
|
1553
|
+
children: [
|
|
1554
|
+
/* @__PURE__ */ jsxDEV7(output.icon, {
|
|
1555
|
+
className: "h-5 w-5 text-[color:var(--blue)]"
|
|
1556
|
+
}, undefined, false, undefined, this),
|
|
1557
|
+
/* @__PURE__ */ jsxDEV7("h3", {
|
|
1558
|
+
className: "mt-5 font-serif text-2xl tracking-[-0.03em]",
|
|
1559
|
+
children: output.title
|
|
1560
|
+
}, undefined, false, undefined, this),
|
|
1561
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1562
|
+
className: "mt-3 text-muted-foreground text-sm leading-7",
|
|
1563
|
+
children: output.copy
|
|
1564
|
+
}, undefined, false, undefined, this)
|
|
1565
|
+
]
|
|
1566
|
+
}, output.title, true, undefined, this))
|
|
1567
|
+
}, undefined, false, undefined, this)
|
|
1568
|
+
]
|
|
1569
|
+
}, undefined, true, undefined, this)
|
|
1570
|
+
}, undefined, false, undefined, this),
|
|
1571
|
+
/* @__PURE__ */ jsxDEV7("section", {
|
|
1572
|
+
className: "editorial-section bg-striped",
|
|
1573
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1574
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[1.1fr_0.9fr]",
|
|
1575
|
+
children: [
|
|
1576
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1577
|
+
className: "editorial-panel space-y-6",
|
|
1578
|
+
children: [
|
|
1579
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1580
|
+
className: "editorial-kicker",
|
|
1581
|
+
children: "Adoption path"
|
|
1582
|
+
}, undefined, false, undefined, this),
|
|
1583
|
+
/* @__PURE__ */ jsxDEV7("h2", {
|
|
1584
|
+
className: "editorial-panel-title",
|
|
1585
|
+
children: "Start where the risk is highest, not where the marketing says to start."
|
|
1586
|
+
}, undefined, false, undefined, this),
|
|
1587
|
+
/* @__PURE__ */ jsxDEV7("ol", {
|
|
1588
|
+
className: "space-y-4",
|
|
1589
|
+
children: adoptionSteps.map((step, index) => /* @__PURE__ */ jsxDEV7("li", {
|
|
1590
|
+
className: "flex gap-4",
|
|
1591
|
+
children: [
|
|
1592
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1593
|
+
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[rgb(162_79_42_/_0.12)] font-mono text-[color:var(--rust)] text-xs",
|
|
1594
|
+
children: [
|
|
1595
|
+
"0",
|
|
1596
|
+
index + 1
|
|
1597
|
+
]
|
|
1598
|
+
}, undefined, true, undefined, this),
|
|
1599
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1600
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
1601
|
+
children: step
|
|
1602
|
+
}, undefined, false, undefined, this)
|
|
1603
|
+
]
|
|
1604
|
+
}, step, true, undefined, this))
|
|
1605
|
+
}, undefined, false, undefined, this)
|
|
1606
|
+
]
|
|
1607
|
+
}, undefined, true, undefined, this),
|
|
1608
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1609
|
+
className: "editorial-panel space-y-6",
|
|
1610
|
+
children: [
|
|
1611
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1612
|
+
className: "editorial-kicker",
|
|
1613
|
+
children: "Studio on top"
|
|
1614
|
+
}, undefined, false, undefined, this),
|
|
1615
|
+
/* @__PURE__ */ jsxDEV7("h2", {
|
|
1616
|
+
className: "editorial-panel-title",
|
|
1617
|
+
children: "Studio is the operating surface, not a replacement identity."
|
|
1618
|
+
}, undefined, false, undefined, this),
|
|
1619
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1620
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
1621
|
+
children: "Use Studio when your team wants a packaged loop for evidence, drafting, review, export, and follow-up. The relationship should feel like the best application built on top of the same open system, not a bait-and-switch away from it."
|
|
1622
|
+
}, undefined, false, undefined, this),
|
|
1623
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1624
|
+
className: "editorial-divider"
|
|
1625
|
+
}, undefined, false, undefined, this),
|
|
1626
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1627
|
+
className: "grid gap-4 text-muted-foreground text-sm",
|
|
1628
|
+
children: [
|
|
1629
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1630
|
+
children: [
|
|
1631
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1632
|
+
className: "font-medium text-foreground",
|
|
1633
|
+
children: "OSS/Core:"
|
|
1634
|
+
}, undefined, false, undefined, this),
|
|
1635
|
+
" ",
|
|
1636
|
+
"contracts, generation, runtimes, harnesses, agent tooling."
|
|
1637
|
+
]
|
|
1638
|
+
}, undefined, true, undefined, this),
|
|
1639
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1640
|
+
children: [
|
|
1641
|
+
/* @__PURE__ */ jsxDEV7("span", {
|
|
1642
|
+
className: "font-medium text-foreground",
|
|
1643
|
+
children: "Studio:"
|
|
1644
|
+
}, undefined, false, undefined, this),
|
|
1645
|
+
" the opinionated operating loop when a team wants the product."
|
|
1646
|
+
]
|
|
1647
|
+
}, undefined, true, undefined, this)
|
|
1648
|
+
]
|
|
1649
|
+
}, undefined, true, undefined, this)
|
|
1650
|
+
]
|
|
1651
|
+
}, undefined, true, undefined, this)
|
|
1652
|
+
]
|
|
1653
|
+
}, undefined, true, undefined, this)
|
|
1654
|
+
}, undefined, false, undefined, this),
|
|
1655
|
+
/* @__PURE__ */ jsxDEV7("section", {
|
|
1656
|
+
className: "section-padding",
|
|
1657
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1658
|
+
className: "editorial-shell",
|
|
1659
|
+
children: /* @__PURE__ */ jsxDEV7("div", {
|
|
1660
|
+
className: "editorial-panel flex flex-col gap-8 rounded-[40px] border-dashed px-6 py-8 md:px-10 md:py-10 lg:flex-row lg:items-end lg:justify-between",
|
|
1661
|
+
children: [
|
|
1662
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1663
|
+
className: "max-w-3xl space-y-4",
|
|
1664
|
+
children: [
|
|
1665
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1666
|
+
className: "editorial-kicker",
|
|
1667
|
+
children: "Choose your path"
|
|
1668
|
+
}, undefined, false, undefined, this),
|
|
1669
|
+
/* @__PURE__ */ jsxDEV7("h2", {
|
|
1670
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
1671
|
+
children: "Adopt the open system first. Evaluate Studio when the team is ready for the operating layer."
|
|
1672
|
+
}, undefined, false, undefined, this),
|
|
1673
|
+
/* @__PURE__ */ jsxDEV7("p", {
|
|
1674
|
+
className: "editorial-copy",
|
|
1675
|
+
children: "That is the product story the site should tell everywhere: open foundation, explicit contracts, safe regeneration, then an opinionated surface on top for teams that want it."
|
|
1676
|
+
}, undefined, false, undefined, this)
|
|
1677
|
+
]
|
|
1678
|
+
}, undefined, true, undefined, this),
|
|
1679
|
+
/* @__PURE__ */ jsxDEV7("div", {
|
|
1680
|
+
className: "flex flex-col gap-3 sm:flex-row lg:flex-col",
|
|
1681
|
+
children: [
|
|
1682
|
+
/* @__PURE__ */ jsxDEV7(Link5, {
|
|
1683
|
+
href: "/install",
|
|
1684
|
+
className: "btn-primary",
|
|
1685
|
+
children: "Start with OSS"
|
|
1686
|
+
}, undefined, false, undefined, this),
|
|
1687
|
+
/* @__PURE__ */ jsxDEV7(Link5, {
|
|
1688
|
+
href: "https://www.contractspec.studio",
|
|
1689
|
+
className: "btn-ghost",
|
|
1690
|
+
children: "Explore Studio"
|
|
1691
|
+
}, undefined, false, undefined, this),
|
|
1692
|
+
/* @__PURE__ */ jsxDEV7(Link5, {
|
|
1693
|
+
href: "/pricing",
|
|
1694
|
+
className: "btn-ghost",
|
|
1695
|
+
children: "See packaging"
|
|
1696
|
+
}, undefined, false, undefined, this)
|
|
1697
|
+
]
|
|
1698
|
+
}, undefined, true, undefined, this)
|
|
1699
|
+
]
|
|
1700
|
+
}, undefined, true, undefined, this)
|
|
1701
|
+
}, undefined, false, undefined, this)
|
|
1702
|
+
}, undefined, false, undefined, this)
|
|
1703
|
+
]
|
|
1704
|
+
}, undefined, true, undefined, this);
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
// src/components/marketing/PricingClient.tsx
|
|
1708
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
1709
|
+
import Link6 from "next/link";
|
|
1710
|
+
import { useState } from "react";
|
|
1711
|
+
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
1712
|
+
"use client";
|
|
1713
|
+
var faqs = [
|
|
1714
|
+
{
|
|
1715
|
+
question: "What stays free?",
|
|
1716
|
+
answer: "The OSS foundation stays free. Teams can adopt contracts, generation, runtime adapters, and the core package ecosystem without crossing into a paid product loop."
|
|
1717
|
+
},
|
|
1718
|
+
{
|
|
1719
|
+
question: "What is Studio charging for?",
|
|
1720
|
+
answer: "Studio is the operating layer: the packaged workflow for evidence, drafts, review, export, and follow-up on top of the same open system."
|
|
1721
|
+
},
|
|
1722
|
+
{
|
|
1723
|
+
question: "Why not price the OSS layer?",
|
|
1724
|
+
answer: "The GTM works better when technical adopters can prove the foundation in the open, keep their leverage, and only pay when the operating product removes enough operational work."
|
|
1725
|
+
},
|
|
1726
|
+
{
|
|
1727
|
+
question: "Who should talk to you now?",
|
|
1728
|
+
answer: "Teams already running AI-heavy product or ops workflows, especially those who feel drift, unsafe regeneration, or coordination pain across multiple surfaces."
|
|
1729
|
+
}
|
|
1730
|
+
];
|
|
1731
|
+
var packages = [
|
|
1732
|
+
{
|
|
1733
|
+
name: "OSS/Core",
|
|
1734
|
+
subtitle: "Free and open",
|
|
1735
|
+
description: "Use the open system when you want explicit contracts, safe regeneration, and standard outputs the team owns.",
|
|
1736
|
+
items: [
|
|
1737
|
+
"Contracts, generation, runtime adapters, harnesses, and agent tooling",
|
|
1738
|
+
"Incremental adoption inside existing codebases",
|
|
1739
|
+
"Local and CI-friendly workflows",
|
|
1740
|
+
"No forced hosted runtime or locked delivery path"
|
|
1741
|
+
],
|
|
1742
|
+
cta: {
|
|
1743
|
+
label: "Start with OSS",
|
|
1744
|
+
href: "/install",
|
|
1745
|
+
className: "btn-primary"
|
|
1746
|
+
}
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
name: "Studio",
|
|
1750
|
+
subtitle: "Operating product",
|
|
1751
|
+
description: "Use Studio when you want the product layer for evidence, drafting, review, exports, and follow-up.",
|
|
1752
|
+
items: [
|
|
1753
|
+
"Packaged operating loop on top of the same open system",
|
|
1754
|
+
"Opinionated team workflows and governance surfaces",
|
|
1755
|
+
"Faster coordination for teams running real product or ops loops",
|
|
1756
|
+
"Design partner and rollout paths for teams with live complexity"
|
|
1757
|
+
],
|
|
1758
|
+
cta: {
|
|
1759
|
+
label: "Explore Studio",
|
|
1760
|
+
href: "https://www.contractspec.studio",
|
|
1761
|
+
className: "btn-ghost"
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
];
|
|
1765
|
+
function PricingClient() {
|
|
1766
|
+
const [openFaq, setOpenFaq] = useState(0);
|
|
1767
|
+
return /* @__PURE__ */ jsxDEV8("main", {
|
|
1768
|
+
children: [
|
|
1769
|
+
/* @__PURE__ */ jsxDEV8("section", {
|
|
1770
|
+
className: "section-padding hero-gradient border-border/70 border-b",
|
|
1771
|
+
children: /* @__PURE__ */ jsxDEV8("div", {
|
|
1772
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[1.05fr_0.95fr]",
|
|
1773
|
+
children: [
|
|
1774
|
+
/* @__PURE__ */ jsxDEV8("div", {
|
|
1775
|
+
className: "space-y-6",
|
|
1776
|
+
children: [
|
|
1777
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1778
|
+
className: "editorial-kicker",
|
|
1779
|
+
children: "Packaging, not upsell fog"
|
|
1780
|
+
}, undefined, false, undefined, this),
|
|
1781
|
+
/* @__PURE__ */ jsxDEV8("h1", {
|
|
1782
|
+
className: "editorial-title max-w-4xl",
|
|
1783
|
+
children: "The open system is how teams start. Studio is how some teams operate."
|
|
1784
|
+
}, undefined, false, undefined, this),
|
|
1785
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1786
|
+
className: "editorial-subtitle",
|
|
1787
|
+
children: "Pricing should reflect the product split honestly. The OSS layer is the open foundation. Studio is the paid operating surface when the team wants a packaged workflow on top."
|
|
1788
|
+
}, undefined, false, undefined, this),
|
|
1789
|
+
/* @__PURE__ */ jsxDEV8("div", {
|
|
1790
|
+
className: "flex flex-col gap-3 sm:flex-row",
|
|
1791
|
+
children: [
|
|
1792
|
+
/* @__PURE__ */ jsxDEV8(Link6, {
|
|
1793
|
+
href: "/install",
|
|
1794
|
+
className: "btn-primary",
|
|
1795
|
+
children: [
|
|
1796
|
+
"Start with OSS ",
|
|
1797
|
+
/* @__PURE__ */ jsxDEV8(ChevronRight, {
|
|
1798
|
+
className: "ml-2 h-4 w-4"
|
|
1799
|
+
}, undefined, false, undefined, this)
|
|
1800
|
+
]
|
|
1801
|
+
}, undefined, true, undefined, this),
|
|
1802
|
+
/* @__PURE__ */ jsxDEV8(Link6, {
|
|
1803
|
+
href: "https://www.contractspec.studio",
|
|
1804
|
+
className: "btn-ghost",
|
|
1805
|
+
children: "Explore Studio"
|
|
1806
|
+
}, undefined, false, undefined, this)
|
|
1807
|
+
]
|
|
1808
|
+
}, undefined, true, undefined, this)
|
|
1809
|
+
]
|
|
1810
|
+
}, undefined, true, undefined, this),
|
|
1811
|
+
/* @__PURE__ */ jsxDEV8("div", {
|
|
1812
|
+
className: "editorial-panel space-y-5",
|
|
1813
|
+
children: [
|
|
1814
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1815
|
+
className: "editorial-kicker",
|
|
1816
|
+
children: "Current GTM"
|
|
1817
|
+
}, undefined, false, undefined, this),
|
|
1818
|
+
/* @__PURE__ */ jsxDEV8("h2", {
|
|
1819
|
+
className: "editorial-panel-title",
|
|
1820
|
+
children: "Earn trust in the open, then earn the right to sell the operating product."
|
|
1821
|
+
}, undefined, false, undefined, this),
|
|
1822
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1823
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
1824
|
+
children: "This page should make the ladder clear: prove the OSS foundation first, then package the workflow that removes operational drag for teams that need more."
|
|
1825
|
+
}, undefined, false, undefined, this)
|
|
1826
|
+
]
|
|
1827
|
+
}, undefined, true, undefined, this)
|
|
1828
|
+
]
|
|
1829
|
+
}, undefined, true, undefined, this)
|
|
1830
|
+
}, undefined, false, undefined, this),
|
|
1831
|
+
/* @__PURE__ */ jsxDEV8("section", {
|
|
1832
|
+
className: "editorial-section",
|
|
1833
|
+
children: /* @__PURE__ */ jsxDEV8("div", {
|
|
1834
|
+
className: "editorial-shell grid gap-6 lg:grid-cols-2",
|
|
1835
|
+
children: packages.map((pkg) => /* @__PURE__ */ jsxDEV8("div", {
|
|
1836
|
+
className: "editorial-panel space-y-6",
|
|
1837
|
+
children: [
|
|
1838
|
+
/* @__PURE__ */ jsxDEV8("div", {
|
|
1839
|
+
className: "space-y-3",
|
|
1840
|
+
children: [
|
|
1841
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1842
|
+
className: "editorial-kicker",
|
|
1843
|
+
children: pkg.subtitle
|
|
1844
|
+
}, undefined, false, undefined, this),
|
|
1845
|
+
/* @__PURE__ */ jsxDEV8("h2", {
|
|
1846
|
+
className: "font-serif text-4xl tracking-[-0.04em]",
|
|
1847
|
+
children: pkg.name
|
|
1848
|
+
}, undefined, false, undefined, this),
|
|
1849
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1850
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
1851
|
+
children: pkg.description
|
|
1852
|
+
}, undefined, false, undefined, this)
|
|
1853
|
+
]
|
|
1854
|
+
}, undefined, true, undefined, this),
|
|
1855
|
+
/* @__PURE__ */ jsxDEV8("ul", {
|
|
1856
|
+
className: "editorial-list",
|
|
1857
|
+
children: pkg.items.map((item) => /* @__PURE__ */ jsxDEV8("li", {
|
|
1858
|
+
children: [
|
|
1859
|
+
/* @__PURE__ */ jsxDEV8("span", {
|
|
1860
|
+
className: "editorial-list-marker"
|
|
1861
|
+
}, undefined, false, undefined, this),
|
|
1862
|
+
/* @__PURE__ */ jsxDEV8("span", {
|
|
1863
|
+
children: item
|
|
1864
|
+
}, undefined, false, undefined, this)
|
|
1865
|
+
]
|
|
1866
|
+
}, item, true, undefined, this))
|
|
1867
|
+
}, undefined, false, undefined, this),
|
|
1868
|
+
/* @__PURE__ */ jsxDEV8(Link6, {
|
|
1869
|
+
href: pkg.cta.href,
|
|
1870
|
+
className: pkg.cta.className,
|
|
1871
|
+
children: pkg.cta.label
|
|
1872
|
+
}, undefined, false, undefined, this)
|
|
1873
|
+
]
|
|
1874
|
+
}, pkg.name, true, undefined, this))
|
|
1875
|
+
}, undefined, false, undefined, this)
|
|
1876
|
+
}, undefined, false, undefined, this),
|
|
1877
|
+
/* @__PURE__ */ jsxDEV8("section", {
|
|
1878
|
+
className: "editorial-section bg-striped",
|
|
1879
|
+
children: /* @__PURE__ */ jsxDEV8("div", {
|
|
1880
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[0.95fr_1.05fr]",
|
|
1881
|
+
children: [
|
|
1882
|
+
/* @__PURE__ */ jsxDEV8("div", {
|
|
1883
|
+
className: "space-y-4",
|
|
1884
|
+
children: [
|
|
1885
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1886
|
+
className: "editorial-kicker",
|
|
1887
|
+
children: "Design partner path"
|
|
1888
|
+
}, undefined, false, undefined, this),
|
|
1889
|
+
/* @__PURE__ */ jsxDEV8("h2", {
|
|
1890
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
1891
|
+
children: "For teams already carrying real AI-native complexity."
|
|
1892
|
+
}, undefined, false, undefined, this),
|
|
1893
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1894
|
+
className: "editorial-copy",
|
|
1895
|
+
children: "The design partner path exists for teams that need the operating layer now and are willing to shape it with us. That is not “enterprise later” positioning. It is a practical way to learn from the hardest live workflows first."
|
|
1896
|
+
}, undefined, false, undefined, this),
|
|
1897
|
+
/* @__PURE__ */ jsxDEV8(Link6, {
|
|
1898
|
+
href: "/design-partner",
|
|
1899
|
+
className: "btn-primary",
|
|
1900
|
+
children: "Apply as a design partner"
|
|
1901
|
+
}, undefined, false, undefined, this)
|
|
1902
|
+
]
|
|
1903
|
+
}, undefined, true, undefined, this),
|
|
1904
|
+
/* @__PURE__ */ jsxDEV8(StudioSignupSection, {}, undefined, false, undefined, this)
|
|
1905
|
+
]
|
|
1906
|
+
}, undefined, true, undefined, this)
|
|
1907
|
+
}, undefined, false, undefined, this),
|
|
1908
|
+
/* @__PURE__ */ jsxDEV8("section", {
|
|
1909
|
+
className: "editorial-section",
|
|
1910
|
+
children: /* @__PURE__ */ jsxDEV8("div", {
|
|
1911
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-[0.9fr_1.1fr]",
|
|
1912
|
+
children: [
|
|
1913
|
+
/* @__PURE__ */ jsxDEV8("div", {
|
|
1914
|
+
className: "space-y-4",
|
|
1915
|
+
children: [
|
|
1916
|
+
/* @__PURE__ */ jsxDEV8("p", {
|
|
1917
|
+
className: "editorial-kicker",
|
|
1918
|
+
children: "FAQ"
|
|
1919
|
+
}, undefined, false, undefined, this),
|
|
1920
|
+
/* @__PURE__ */ jsxDEV8("h2", {
|
|
1921
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
1922
|
+
children: "Questions teams usually ask before they pick a side."
|
|
1923
|
+
}, undefined, false, undefined, this)
|
|
1924
|
+
]
|
|
1925
|
+
}, undefined, true, undefined, this),
|
|
1926
|
+
/* @__PURE__ */ jsxDEV8("div", {
|
|
1927
|
+
className: "space-y-3",
|
|
1928
|
+
children: faqs.map((faq, index) => {
|
|
1929
|
+
const isOpen = openFaq === index;
|
|
1930
|
+
return /* @__PURE__ */ jsxDEV8("div", {
|
|
1931
|
+
className: "editorial-panel p-5",
|
|
1932
|
+
children: [
|
|
1933
|
+
/* @__PURE__ */ jsxDEV8("button", {
|
|
1934
|
+
type: "button",
|
|
1935
|
+
onClick: () => setOpenFaq(isOpen ? null : index),
|
|
1936
|
+
className: "flex w-full items-center justify-between gap-4 text-left",
|
|
1937
|
+
children: [
|
|
1938
|
+
/* @__PURE__ */ jsxDEV8("span", {
|
|
1939
|
+
className: "font-medium text-lg",
|
|
1940
|
+
children: faq.question
|
|
1941
|
+
}, undefined, false, undefined, this),
|
|
1942
|
+
/* @__PURE__ */ jsxDEV8(ChevronDown, {
|
|
1943
|
+
className: `h-4 w-4 shrink-0 text-muted-foreground transition-transform ${isOpen ? "rotate-180" : ""}`
|
|
1944
|
+
}, undefined, false, undefined, this)
|
|
1945
|
+
]
|
|
1946
|
+
}, undefined, true, undefined, this),
|
|
1947
|
+
isOpen ? /* @__PURE__ */ jsxDEV8("p", {
|
|
1948
|
+
className: "mt-4 text-muted-foreground text-sm leading-7",
|
|
1949
|
+
children: faq.answer
|
|
1950
|
+
}, undefined, false, undefined, this) : null
|
|
1951
|
+
]
|
|
1952
|
+
}, faq.question, true, undefined, this);
|
|
1953
|
+
})
|
|
1954
|
+
}, undefined, false, undefined, this)
|
|
1955
|
+
]
|
|
1956
|
+
}, undefined, true, undefined, this)
|
|
1957
|
+
}, undefined, false, undefined, this)
|
|
1958
|
+
]
|
|
1959
|
+
}, undefined, true, undefined, this);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/components/marketing/ProductClientPage.tsx
|
|
1963
|
+
import {
|
|
1964
|
+
analyticsEventNames,
|
|
1965
|
+
captureAnalyticsEvent
|
|
1966
|
+
} from "@contractspec/bundle.library/libs/posthog/client";
|
|
1967
|
+
import {
|
|
1968
|
+
ArrowRight as ArrowRight3,
|
|
1969
|
+
Blocks as Blocks2,
|
|
1970
|
+
Bot as Bot2,
|
|
1971
|
+
Braces as Braces2,
|
|
1972
|
+
Captions,
|
|
1973
|
+
CheckCircle2,
|
|
1974
|
+
ClipboardCheck,
|
|
1975
|
+
Layers3,
|
|
1976
|
+
ShieldCheck as ShieldCheck2,
|
|
1977
|
+
Sparkles as Sparkles3
|
|
1978
|
+
} from "lucide-react";
|
|
1979
|
+
import Link7 from "next/link";
|
|
1980
|
+
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
1981
|
+
"use client";
|
|
1982
|
+
var layers = [
|
|
1983
|
+
{
|
|
1984
|
+
name: "Contracts and specs",
|
|
1985
|
+
copy: "The canonical product rules your team wants the system to keep respecting over time.",
|
|
1986
|
+
icon: Braces2
|
|
1987
|
+
},
|
|
1988
|
+
{
|
|
1989
|
+
name: "Generation and runtime bridges",
|
|
1990
|
+
copy: "The adapters that turn those rules into API, UI, data, event, MCP, and client-facing surfaces.",
|
|
1991
|
+
icon: Layers3
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
name: "Harness and proof workflows",
|
|
1995
|
+
copy: "The inspection, replay, evaluation, and evidence surfaces that tell you whether automation is safe.",
|
|
1996
|
+
icon: ClipboardCheck
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
name: "Studio operating product",
|
|
2000
|
+
copy: "The opinionated team workflow for running evidence, drafts, review, exports, and checks on top of the same foundation.",
|
|
2001
|
+
icon: Sparkles3
|
|
2002
|
+
}
|
|
2003
|
+
];
|
|
2004
|
+
var comparison = [
|
|
2005
|
+
{
|
|
2006
|
+
label: "OSS/Core",
|
|
2007
|
+
points: [
|
|
2008
|
+
"You want explicit contracts, safe regeneration, and standards-first outputs.",
|
|
2009
|
+
"You need to stabilize an existing product incrementally.",
|
|
2010
|
+
"You want the foundation without being forced into a hosted product loop."
|
|
2011
|
+
]
|
|
2012
|
+
},
|
|
2013
|
+
{
|
|
2014
|
+
label: "Studio",
|
|
2015
|
+
points: [
|
|
2016
|
+
"You want the operating surface for evidence, drafts, review, exports, and follow-up.",
|
|
2017
|
+
"You want packaged workflows and coordination on top of the same contract system.",
|
|
2018
|
+
"You want the product that absorbs more operational complexity for the team."
|
|
2019
|
+
]
|
|
2020
|
+
}
|
|
2021
|
+
];
|
|
2022
|
+
var proofs = [
|
|
2023
|
+
{
|
|
2024
|
+
label: "Explicit contracts, not inferred conventions",
|
|
2025
|
+
icon: ShieldCheck2
|
|
2026
|
+
},
|
|
2027
|
+
{
|
|
2028
|
+
label: "Standard outputs the team can own and change",
|
|
2029
|
+
icon: Bot2
|
|
2030
|
+
},
|
|
2031
|
+
{
|
|
2032
|
+
label: "Multi-surface consistency across API, UI, data, and tools",
|
|
2033
|
+
icon: Blocks2
|
|
2034
|
+
},
|
|
2035
|
+
{
|
|
2036
|
+
label: "Incremental adoption instead of rewrite-only adoption",
|
|
2037
|
+
icon: Captions
|
|
2038
|
+
}
|
|
2039
|
+
];
|
|
2040
|
+
function trackInstall() {
|
|
2041
|
+
captureAnalyticsEvent(analyticsEventNames.CTA_INSTALL_CLICK, {
|
|
2042
|
+
surface: "product-hero"
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
function trackStudio() {
|
|
2046
|
+
captureAnalyticsEvent(analyticsEventNames.CTA_STUDIO_CLICK, {
|
|
2047
|
+
surface: "product-hero"
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
var ProductClientPage = () => /* @__PURE__ */ jsxDEV9("main", {
|
|
2051
|
+
children: [
|
|
2052
|
+
/* @__PURE__ */ jsxDEV9("section", {
|
|
2053
|
+
className: "section-padding hero-gradient border-border/70 border-b",
|
|
2054
|
+
children: /* @__PURE__ */ jsxDEV9("div", {
|
|
2055
|
+
className: "editorial-shell grid gap-10 lg:grid-cols-[1.05fr_0.95fr]",
|
|
2056
|
+
children: [
|
|
2057
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2058
|
+
className: "space-y-6",
|
|
2059
|
+
children: [
|
|
2060
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2061
|
+
className: "editorial-kicker",
|
|
2062
|
+
children: "Product overview"
|
|
2063
|
+
}, undefined, false, undefined, this),
|
|
2064
|
+
/* @__PURE__ */ jsxDEV9("h1", {
|
|
2065
|
+
className: "editorial-title max-w-4xl",
|
|
2066
|
+
children: "An open system for keeping AI-native products coherent."
|
|
2067
|
+
}, undefined, false, undefined, this),
|
|
2068
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2069
|
+
className: "editorial-subtitle",
|
|
2070
|
+
children: "ContractSpec is not one narrow generator. It is the explicit layer that lets teams define system behavior, keep multiple surfaces aligned, regenerate safely, and move into Studio when they want the operating product."
|
|
2071
|
+
}, undefined, false, undefined, this),
|
|
2072
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2073
|
+
className: "flex flex-col gap-3 sm:flex-row",
|
|
2074
|
+
children: [
|
|
2075
|
+
/* @__PURE__ */ jsxDEV9(Link7, {
|
|
2076
|
+
href: "/install",
|
|
2077
|
+
className: "btn-primary",
|
|
2078
|
+
onClick: trackInstall,
|
|
2079
|
+
children: [
|
|
2080
|
+
"Start with OSS ",
|
|
2081
|
+
/* @__PURE__ */ jsxDEV9(ArrowRight3, {
|
|
2082
|
+
className: "ml-2 h-4 w-4"
|
|
2083
|
+
}, undefined, false, undefined, this)
|
|
2084
|
+
]
|
|
2085
|
+
}, undefined, true, undefined, this),
|
|
2086
|
+
/* @__PURE__ */ jsxDEV9(Link7, {
|
|
2087
|
+
href: "https://www.contractspec.studio",
|
|
2088
|
+
className: "btn-ghost",
|
|
2089
|
+
onClick: trackStudio,
|
|
2090
|
+
children: "Explore Studio"
|
|
2091
|
+
}, undefined, false, undefined, this)
|
|
2092
|
+
]
|
|
2093
|
+
}, undefined, true, undefined, this)
|
|
2094
|
+
]
|
|
2095
|
+
}, undefined, true, undefined, this),
|
|
2096
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2097
|
+
className: "editorial-panel space-y-5",
|
|
2098
|
+
children: [
|
|
2099
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2100
|
+
className: "editorial-kicker",
|
|
2101
|
+
children: "What the category really is"
|
|
2102
|
+
}, undefined, false, undefined, this),
|
|
2103
|
+
/* @__PURE__ */ jsxDEV9("h2", {
|
|
2104
|
+
className: "editorial-panel-title",
|
|
2105
|
+
children: "Lead with the system, not just the generation step."
|
|
2106
|
+
}, undefined, false, undefined, this),
|
|
2107
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2108
|
+
className: "text-muted-foreground text-sm leading-7",
|
|
2109
|
+
children: "Generation matters, but it is not the whole story. The real value is that contracts, runtime adapters, proof surfaces, and the Studio operating loop all remain legible as parts of the same product system."
|
|
2110
|
+
}, undefined, false, undefined, this),
|
|
2111
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2112
|
+
className: "editorial-divider"
|
|
2113
|
+
}, undefined, false, undefined, this),
|
|
2114
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2115
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
2116
|
+
children: [
|
|
2117
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2118
|
+
className: "rounded-[24px] border border-border/70 bg-muted/45 p-4",
|
|
2119
|
+
children: [
|
|
2120
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2121
|
+
className: "editorial-label",
|
|
2122
|
+
children: "Better umbrella"
|
|
2123
|
+
}, undefined, false, undefined, this),
|
|
2124
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2125
|
+
className: "mt-2 font-medium text-sm",
|
|
2126
|
+
children: "Open spec system for AI-native software"
|
|
2127
|
+
}, undefined, false, undefined, this)
|
|
2128
|
+
]
|
|
2129
|
+
}, undefined, true, undefined, this),
|
|
2130
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2131
|
+
className: "rounded-[24px] border border-border/70 bg-muted/45 p-4",
|
|
2132
|
+
children: [
|
|
2133
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2134
|
+
className: "editorial-label",
|
|
2135
|
+
children: "Where “compiler” belongs"
|
|
2136
|
+
}, undefined, false, undefined, this),
|
|
2137
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2138
|
+
className: "mt-2 font-medium text-sm",
|
|
2139
|
+
children: "Inside the technical proof, not as the whole company category"
|
|
2140
|
+
}, undefined, false, undefined, this)
|
|
2141
|
+
]
|
|
2142
|
+
}, undefined, true, undefined, this)
|
|
2143
|
+
]
|
|
2144
|
+
}, undefined, true, undefined, this)
|
|
2145
|
+
]
|
|
2146
|
+
}, undefined, true, undefined, this)
|
|
2147
|
+
]
|
|
2148
|
+
}, undefined, true, undefined, this)
|
|
2149
|
+
}, undefined, false, undefined, this),
|
|
2150
|
+
/* @__PURE__ */ jsxDEV9("section", {
|
|
2151
|
+
className: "editorial-section",
|
|
2152
|
+
children: /* @__PURE__ */ jsxDEV9("div", {
|
|
2153
|
+
className: "editorial-shell space-y-8",
|
|
2154
|
+
children: [
|
|
2155
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2156
|
+
className: "max-w-3xl space-y-4",
|
|
2157
|
+
children: [
|
|
2158
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2159
|
+
className: "editorial-kicker",
|
|
2160
|
+
children: "Architecture by layer"
|
|
2161
|
+
}, undefined, false, undefined, this),
|
|
2162
|
+
/* @__PURE__ */ jsxDEV9("h2", {
|
|
2163
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
2164
|
+
children: "Each layer exists to keep the next one from drifting."
|
|
2165
|
+
}, undefined, false, undefined, this),
|
|
2166
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2167
|
+
className: "editorial-copy",
|
|
2168
|
+
children: "The repo structure already tells the right story: lower layers define explicit behavior, higher layers compose that behavior into working surfaces, and apps stay thin."
|
|
2169
|
+
}, undefined, false, undefined, this)
|
|
2170
|
+
]
|
|
2171
|
+
}, undefined, true, undefined, this),
|
|
2172
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2173
|
+
className: "grid gap-5 md:grid-cols-2 xl:grid-cols-4",
|
|
2174
|
+
children: layers.map((layer) => /* @__PURE__ */ jsxDEV9("div", {
|
|
2175
|
+
className: "editorial-panel",
|
|
2176
|
+
children: [
|
|
2177
|
+
/* @__PURE__ */ jsxDEV9(layer.icon, {
|
|
2178
|
+
className: "h-5 w-5 text-[color:var(--rust)]"
|
|
2179
|
+
}, undefined, false, undefined, this),
|
|
2180
|
+
/* @__PURE__ */ jsxDEV9("h3", {
|
|
2181
|
+
className: "mt-5 font-serif text-2xl tracking-[-0.03em]",
|
|
2182
|
+
children: layer.name
|
|
2183
|
+
}, undefined, false, undefined, this),
|
|
2184
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2185
|
+
className: "mt-3 text-muted-foreground text-sm leading-7",
|
|
2186
|
+
children: layer.copy
|
|
2187
|
+
}, undefined, false, undefined, this)
|
|
2188
|
+
]
|
|
2189
|
+
}, layer.name, true, undefined, this))
|
|
2190
|
+
}, undefined, false, undefined, this)
|
|
2191
|
+
]
|
|
2192
|
+
}, undefined, true, undefined, this)
|
|
2193
|
+
}, undefined, false, undefined, this),
|
|
2194
|
+
/* @__PURE__ */ jsxDEV9("section", {
|
|
2195
|
+
className: "editorial-section bg-striped",
|
|
2196
|
+
children: /* @__PURE__ */ jsxDEV9("div", {
|
|
2197
|
+
className: "editorial-shell grid gap-8 lg:grid-cols-2",
|
|
2198
|
+
children: comparison.map((column) => /* @__PURE__ */ jsxDEV9("div", {
|
|
2199
|
+
className: "editorial-panel",
|
|
2200
|
+
children: [
|
|
2201
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2202
|
+
className: "editorial-kicker",
|
|
2203
|
+
children: column.label
|
|
2204
|
+
}, undefined, false, undefined, this),
|
|
2205
|
+
/* @__PURE__ */ jsxDEV9("h2", {
|
|
2206
|
+
className: "mt-3 font-serif text-3xl tracking-[-0.04em]",
|
|
2207
|
+
children: column.label === "OSS/Core" ? "Adopt the open foundation first" : "Add the operating product when the team is ready"
|
|
2208
|
+
}, undefined, false, undefined, this),
|
|
2209
|
+
/* @__PURE__ */ jsxDEV9("ul", {
|
|
2210
|
+
className: "editorial-list mt-6",
|
|
2211
|
+
children: column.points.map((point) => /* @__PURE__ */ jsxDEV9("li", {
|
|
2212
|
+
children: [
|
|
2213
|
+
/* @__PURE__ */ jsxDEV9(CheckCircle2, {
|
|
2214
|
+
className: "mt-1.5 h-4 w-4 shrink-0 text-[color:var(--success)]"
|
|
2215
|
+
}, undefined, false, undefined, this),
|
|
2216
|
+
/* @__PURE__ */ jsxDEV9("span", {
|
|
2217
|
+
children: point
|
|
2218
|
+
}, undefined, false, undefined, this)
|
|
2219
|
+
]
|
|
2220
|
+
}, point, true, undefined, this))
|
|
2221
|
+
}, undefined, false, undefined, this)
|
|
2222
|
+
]
|
|
2223
|
+
}, column.label, true, undefined, this))
|
|
2224
|
+
}, undefined, false, undefined, this)
|
|
2225
|
+
}, undefined, false, undefined, this),
|
|
2226
|
+
/* @__PURE__ */ jsxDEV9("section", {
|
|
2227
|
+
className: "editorial-section",
|
|
2228
|
+
children: /* @__PURE__ */ jsxDEV9("div", {
|
|
2229
|
+
className: "editorial-shell grid gap-10 lg:grid-cols-[0.9fr_1.1fr]",
|
|
2230
|
+
children: [
|
|
2231
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2232
|
+
className: "space-y-4",
|
|
2233
|
+
children: [
|
|
2234
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2235
|
+
className: "editorial-kicker",
|
|
2236
|
+
children: "Proof points"
|
|
2237
|
+
}, undefined, false, undefined, this),
|
|
2238
|
+
/* @__PURE__ */ jsxDEV9("h2", {
|
|
2239
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
2240
|
+
children: "What should feel different after adoption."
|
|
2241
|
+
}, undefined, false, undefined, this),
|
|
2242
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2243
|
+
className: "editorial-copy",
|
|
2244
|
+
children: "The point is not just faster output. The point is that regeneration, refactoring, and agent behavior stop feeling opaque because the team has an explicit layer it can inspect and trust."
|
|
2245
|
+
}, undefined, false, undefined, this)
|
|
2246
|
+
]
|
|
2247
|
+
}, undefined, true, undefined, this),
|
|
2248
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2249
|
+
className: "grid gap-5 md:grid-cols-2",
|
|
2250
|
+
children: proofs.map((proof) => {
|
|
2251
|
+
const Icon = proof.icon;
|
|
2252
|
+
return /* @__PURE__ */ jsxDEV9("div", {
|
|
2253
|
+
className: "editorial-panel",
|
|
2254
|
+
children: [
|
|
2255
|
+
/* @__PURE__ */ jsxDEV9(Icon, {
|
|
2256
|
+
className: "h-5 w-5 text-[color:var(--blue)]"
|
|
2257
|
+
}, undefined, false, undefined, this),
|
|
2258
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2259
|
+
className: "mt-5 font-medium text-lg",
|
|
2260
|
+
children: proof.label
|
|
2261
|
+
}, undefined, false, undefined, this)
|
|
2262
|
+
]
|
|
2263
|
+
}, proof.label, true, undefined, this);
|
|
2264
|
+
})
|
|
2265
|
+
}, undefined, false, undefined, this)
|
|
2266
|
+
]
|
|
2267
|
+
}, undefined, true, undefined, this)
|
|
2268
|
+
}, undefined, false, undefined, this),
|
|
2269
|
+
/* @__PURE__ */ jsxDEV9("section", {
|
|
2270
|
+
className: "section-padding",
|
|
2271
|
+
children: /* @__PURE__ */ jsxDEV9("div", {
|
|
2272
|
+
className: "editorial-shell",
|
|
2273
|
+
children: /* @__PURE__ */ jsxDEV9("div", {
|
|
2274
|
+
className: "editorial-panel flex flex-col gap-8 rounded-[38px] border-dashed md:flex-row md:items-end md:justify-between",
|
|
2275
|
+
children: [
|
|
2276
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2277
|
+
className: "max-w-3xl space-y-4",
|
|
2278
|
+
children: [
|
|
2279
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2280
|
+
className: "editorial-kicker",
|
|
2281
|
+
children: "Next step"
|
|
2282
|
+
}, undefined, false, undefined, this),
|
|
2283
|
+
/* @__PURE__ */ jsxDEV9("h2", {
|
|
2284
|
+
className: "font-serif text-4xl tracking-[-0.04em] md:text-5xl",
|
|
2285
|
+
children: "Use the OSS layer when you want control. Use Studio when you want the operating loop."
|
|
2286
|
+
}, undefined, false, undefined, this),
|
|
2287
|
+
/* @__PURE__ */ jsxDEV9("p", {
|
|
2288
|
+
className: "editorial-copy",
|
|
2289
|
+
children: "That is the cleanest product split for both technical adopters and teams buying the packaged surface later."
|
|
2290
|
+
}, undefined, false, undefined, this)
|
|
2291
|
+
]
|
|
2292
|
+
}, undefined, true, undefined, this),
|
|
2293
|
+
/* @__PURE__ */ jsxDEV9("div", {
|
|
2294
|
+
className: "flex flex-col gap-3 sm:flex-row md:flex-col",
|
|
2295
|
+
children: [
|
|
2296
|
+
/* @__PURE__ */ jsxDEV9(Link7, {
|
|
2297
|
+
href: "/install",
|
|
2298
|
+
className: "btn-primary",
|
|
2299
|
+
onClick: trackInstall,
|
|
2300
|
+
children: "Start with OSS"
|
|
2301
|
+
}, undefined, false, undefined, this),
|
|
2302
|
+
/* @__PURE__ */ jsxDEV9(Link7, {
|
|
2303
|
+
href: "https://www.contractspec.studio",
|
|
2304
|
+
className: "btn-ghost",
|
|
2305
|
+
onClick: trackStudio,
|
|
2306
|
+
children: "Explore Studio"
|
|
2307
|
+
}, undefined, false, undefined, this)
|
|
2308
|
+
]
|
|
2309
|
+
}, undefined, true, undefined, this)
|
|
2310
|
+
]
|
|
2311
|
+
}, undefined, true, undefined, this)
|
|
2312
|
+
}, undefined, false, undefined, this)
|
|
2313
|
+
}, undefined, false, undefined, this)
|
|
2314
|
+
]
|
|
2315
|
+
}, undefined, true, undefined, this);
|
|
2316
|
+
|
|
2317
|
+
// src/libs/pricing-examples.ts
|
|
2318
|
+
var PRICING_EXAMPLES = {
|
|
2319
|
+
free: {
|
|
2320
|
+
regenerationsPerMonth: 200,
|
|
2321
|
+
aiActionsPerMonth: 100,
|
|
2322
|
+
projects: 1
|
|
2323
|
+
},
|
|
2324
|
+
builder: {
|
|
2325
|
+
regenerationsPerMonthHint: "1,000–2,000+",
|
|
2326
|
+
aiActionsPerMonthHint: "1,000+"
|
|
2327
|
+
},
|
|
2328
|
+
team: {
|
|
2329
|
+
description: "Higher limits + cheaper per-regen at scale"
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
|
|
2333
|
+
// src/components/marketing/pricing-thinking-modal.tsx
|
|
2334
|
+
import { Button as Button2 } from "@contractspec/lib.design-system";
|
|
2335
|
+
import {
|
|
2336
|
+
Dialog,
|
|
2337
|
+
DialogContent,
|
|
2338
|
+
DialogDescription,
|
|
2339
|
+
DialogHeader,
|
|
2340
|
+
DialogTitle
|
|
2341
|
+
} from "@contractspec/lib.ui-kit-web/ui/dialog";
|
|
2342
|
+
import { CheckCircle as CheckCircle3 } from "lucide-react";
|
|
2343
|
+
import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
|
|
2344
|
+
"use client";
|
|
2345
|
+
var pricingTiers = [
|
|
2346
|
+
{
|
|
2347
|
+
tag: "Planned",
|
|
2348
|
+
title: "Free",
|
|
2349
|
+
priceLine: "For hobbyists and pre-PMF teams",
|
|
2350
|
+
bullets: [
|
|
2351
|
+
"1 active project",
|
|
2352
|
+
"Small spec size",
|
|
2353
|
+
`Example: ~${PRICING_EXAMPLES.free.regenerationsPerMonth} free regenerations per month`,
|
|
2354
|
+
`Example: ~${PRICING_EXAMPLES.free.aiActionsPerMonth} free AI agent actions per month`,
|
|
2355
|
+
"Unlimited collaborators"
|
|
2356
|
+
],
|
|
2357
|
+
note: "Good enough to build and launch a real product before paying."
|
|
2358
|
+
},
|
|
2359
|
+
{
|
|
2360
|
+
tag: "Planned",
|
|
2361
|
+
title: "Builder",
|
|
2362
|
+
priceLine: "Usage-based, for solo builders and small teams",
|
|
2363
|
+
bullets: [
|
|
2364
|
+
"More projects",
|
|
2365
|
+
`More monthly regenerations included (e.g. ${PRICING_EXAMPLES.builder.regenerationsPerMonthHint})`,
|
|
2366
|
+
`More AI agent actions included (e.g. ${PRICING_EXAMPLES.builder.aiActionsPerMonthHint})`,
|
|
2367
|
+
"Pay-as-you-go for extra regenerations and AI",
|
|
2368
|
+
"Basic environments (dev / prod)"
|
|
2369
|
+
],
|
|
2370
|
+
note: "Pay for how fast and how often you evolve your system, not for seats."
|
|
2371
|
+
},
|
|
2372
|
+
{
|
|
2373
|
+
tag: "Planned",
|
|
2374
|
+
title: "Team & Platform",
|
|
2375
|
+
priceLine: "For teams standardizing on ContractSpec",
|
|
2376
|
+
bullets: [
|
|
2377
|
+
"Multiple projects and environments",
|
|
2378
|
+
"Higher regeneration and AI action limits",
|
|
2379
|
+
"Cheaper overages as you scale",
|
|
2380
|
+
"Advanced RBAC and governance",
|
|
2381
|
+
"SSO, audit trails, and longer retention"
|
|
2382
|
+
],
|
|
2383
|
+
note: "For platform teams using ContractSpec as infra for multiple apps."
|
|
2384
|
+
}
|
|
2385
|
+
];
|
|
2386
|
+
var usageMetrics = [
|
|
2387
|
+
{
|
|
2388
|
+
name: "Regenerations",
|
|
2389
|
+
freeTier: `Free tier: e.g. ~${PRICING_EXAMPLES.free.regenerationsPerMonth} regenerations / month`,
|
|
2390
|
+
beyond: "Beyond: pay per additional regeneration, with volume discounts."
|
|
2391
|
+
},
|
|
2392
|
+
{
|
|
2393
|
+
name: "AI agent actions",
|
|
2394
|
+
freeTier: `Free tier: e.g. ~${PRICING_EXAMPLES.free.aiActionsPerMonth} AI agent actions / month`,
|
|
2395
|
+
beyond: "Beyond: pay-as-you-go for extra AI usage."
|
|
2396
|
+
},
|
|
2397
|
+
{
|
|
2398
|
+
name: "Projects",
|
|
2399
|
+
freeTier: `Free tier: ${PRICING_EXAMPLES.free.projects} project`,
|
|
2400
|
+
beyond: "Builder / Team: more projects included; extra projects available as you scale."
|
|
2401
|
+
}
|
|
2402
|
+
];
|
|
2403
|
+
function PricingThinkingModal({
|
|
2404
|
+
open,
|
|
2405
|
+
onOpenChange,
|
|
2406
|
+
onApplyClick
|
|
2407
|
+
}) {
|
|
2408
|
+
return /* @__PURE__ */ jsxDEV10(Dialog, {
|
|
2409
|
+
open,
|
|
2410
|
+
onOpenChange,
|
|
2411
|
+
children: /* @__PURE__ */ jsxDEV10(DialogContent, {
|
|
2412
|
+
className: "max-h-[90vh] w-full overflow-y-auto md:max-w-5xl",
|
|
2413
|
+
children: [
|
|
2414
|
+
/* @__PURE__ */ jsxDEV10(DialogHeader, {
|
|
2415
|
+
children: [
|
|
2416
|
+
/* @__PURE__ */ jsxDEV10(DialogTitle, {
|
|
2417
|
+
children: "Tentative pricing (work in progress)"
|
|
2418
|
+
}, undefined, false, undefined, this),
|
|
2419
|
+
/* @__PURE__ */ jsxDEV10(DialogDescription, {
|
|
2420
|
+
children: "ContractSpec Studio is live. This is a draft of how paid plans are expected to evolve as usage grows."
|
|
2421
|
+
}, undefined, false, undefined, this)
|
|
2422
|
+
]
|
|
2423
|
+
}, undefined, true, undefined, this),
|
|
2424
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2425
|
+
className: "space-y-8",
|
|
2426
|
+
children: [
|
|
2427
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2428
|
+
className: "space-y-4",
|
|
2429
|
+
children: [
|
|
2430
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2431
|
+
className: "flex items-center gap-2",
|
|
2432
|
+
children: [
|
|
2433
|
+
/* @__PURE__ */ jsxDEV10("span", {
|
|
2434
|
+
className: "font-medium text-muted-foreground text-xs",
|
|
2435
|
+
children: "Draft"
|
|
2436
|
+
}, undefined, false, undefined, this),
|
|
2437
|
+
/* @__PURE__ */ jsxDEV10("span", {
|
|
2438
|
+
className: "text-muted-foreground text-xs",
|
|
2439
|
+
children: "•"
|
|
2440
|
+
}, undefined, false, undefined, this),
|
|
2441
|
+
/* @__PURE__ */ jsxDEV10("span", {
|
|
2442
|
+
className: "text-muted-foreground text-xs",
|
|
2443
|
+
children: "Subject to change"
|
|
2444
|
+
}, undefined, false, undefined, this)
|
|
2445
|
+
]
|
|
2446
|
+
}, undefined, true, undefined, this),
|
|
2447
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2448
|
+
className: "grid gap-4 md:grid-cols-3",
|
|
2449
|
+
children: pricingTiers.map((tier) => /* @__PURE__ */ jsxDEV10("div", {
|
|
2450
|
+
className: "card-subtle relative space-y-4 p-6",
|
|
2451
|
+
children: [
|
|
2452
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2453
|
+
className: "absolute -top-2 left-1/2 -translate-x-1/2 rounded-full border border-border bg-muted px-2 py-0.5 font-medium text-xs",
|
|
2454
|
+
children: tier.tag
|
|
2455
|
+
}, undefined, false, undefined, this),
|
|
2456
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2457
|
+
className: "space-y-2 pt-2",
|
|
2458
|
+
children: [
|
|
2459
|
+
/* @__PURE__ */ jsxDEV10("h3", {
|
|
2460
|
+
className: "font-bold text-xl",
|
|
2461
|
+
children: tier.title
|
|
2462
|
+
}, undefined, false, undefined, this),
|
|
2463
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2464
|
+
className: "text-muted-foreground text-sm",
|
|
2465
|
+
children: tier.priceLine
|
|
2466
|
+
}, undefined, false, undefined, this)
|
|
2467
|
+
]
|
|
2468
|
+
}, undefined, true, undefined, this),
|
|
2469
|
+
/* @__PURE__ */ jsxDEV10("ul", {
|
|
2470
|
+
className: "space-y-2",
|
|
2471
|
+
children: tier.bullets.map((bullet, i) => /* @__PURE__ */ jsxDEV10("li", {
|
|
2472
|
+
className: "flex gap-2 text-muted-foreground text-sm",
|
|
2473
|
+
children: [
|
|
2474
|
+
/* @__PURE__ */ jsxDEV10(CheckCircle3, {
|
|
2475
|
+
size: 14,
|
|
2476
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
2477
|
+
}, undefined, false, undefined, this),
|
|
2478
|
+
bullet
|
|
2479
|
+
]
|
|
2480
|
+
}, i, true, undefined, this))
|
|
2481
|
+
}, undefined, false, undefined, this),
|
|
2482
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2483
|
+
className: "text-muted-foreground text-xs italic",
|
|
2484
|
+
children: tier.note
|
|
2485
|
+
}, undefined, false, undefined, this)
|
|
2486
|
+
]
|
|
2487
|
+
}, tier.title, true, undefined, this))
|
|
2488
|
+
}, undefined, false, undefined, this)
|
|
2489
|
+
]
|
|
2490
|
+
}, undefined, true, undefined, this),
|
|
2491
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2492
|
+
className: "space-y-4 border-border border-t pt-6",
|
|
2493
|
+
children: [
|
|
2494
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2495
|
+
children: [
|
|
2496
|
+
/* @__PURE__ */ jsxDEV10("h3", {
|
|
2497
|
+
className: "font-bold text-lg",
|
|
2498
|
+
children: "Usage-based, with a generous free tier"
|
|
2499
|
+
}, undefined, false, undefined, this),
|
|
2500
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2501
|
+
className: "mt-2 text-muted-foreground text-sm",
|
|
2502
|
+
children: "Inspired by products like PostHog, we plan to keep a generous free tier on all plans, then charge based on actual usage: regenerations, AI agent actions, and the number of projects you run on ContractSpec."
|
|
2503
|
+
}, undefined, false, undefined, this),
|
|
2504
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2505
|
+
className: "mt-3 text-muted-foreground text-xs italic",
|
|
2506
|
+
children: "Free tier limits are intentionally small but useful: enough to try the agent and regenerate a real project, not enough to run a full team's workload for free."
|
|
2507
|
+
}, undefined, false, undefined, this)
|
|
2508
|
+
]
|
|
2509
|
+
}, undefined, true, undefined, this),
|
|
2510
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2511
|
+
className: "grid gap-4 md:grid-cols-3",
|
|
2512
|
+
children: usageMetrics.map((metric) => /* @__PURE__ */ jsxDEV10("div", {
|
|
2513
|
+
className: "card-subtle space-y-2 p-4",
|
|
2514
|
+
children: [
|
|
2515
|
+
/* @__PURE__ */ jsxDEV10("h4", {
|
|
2516
|
+
className: "font-semibold text-sm",
|
|
2517
|
+
children: metric.name
|
|
2518
|
+
}, undefined, false, undefined, this),
|
|
2519
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2520
|
+
className: "text-muted-foreground text-xs",
|
|
2521
|
+
children: metric.freeTier
|
|
2522
|
+
}, undefined, false, undefined, this),
|
|
2523
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2524
|
+
className: "text-muted-foreground text-xs",
|
|
2525
|
+
children: metric.beyond
|
|
2526
|
+
}, undefined, false, undefined, this)
|
|
2527
|
+
]
|
|
2528
|
+
}, metric.name, true, undefined, this))
|
|
2529
|
+
}, undefined, false, undefined, this)
|
|
2530
|
+
]
|
|
2531
|
+
}, undefined, true, undefined, this),
|
|
2532
|
+
/* @__PURE__ */ jsxDEV10("div", {
|
|
2533
|
+
className: "space-y-4 border-border border-t pt-6",
|
|
2534
|
+
children: [
|
|
2535
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2536
|
+
className: "text-muted-foreground text-xs",
|
|
2537
|
+
children: "These numbers are examples only. Final pricing and limits will evolve as we learn from design partners."
|
|
2538
|
+
}, undefined, false, undefined, this),
|
|
2539
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2540
|
+
className: "text-muted-foreground text-xs",
|
|
2541
|
+
children: "This is a tentative pricing model. We're pre-PMF and pricing is still in draft, subject to change based on what we learn."
|
|
2542
|
+
}, undefined, false, undefined, this),
|
|
2543
|
+
/* @__PURE__ */ jsxDEV10("p", {
|
|
2544
|
+
className: "text-muted-foreground text-xs",
|
|
2545
|
+
children: "Design partners get priority onboarding and partner incentives as paid plans launch."
|
|
2546
|
+
}, undefined, false, undefined, this),
|
|
2547
|
+
onApplyClick && /* @__PURE__ */ jsxDEV10(Button2, {
|
|
2548
|
+
onClick: () => {
|
|
2549
|
+
onOpenChange(false);
|
|
2550
|
+
onApplyClick();
|
|
2551
|
+
},
|
|
2552
|
+
className: "w-full",
|
|
2553
|
+
variant: "outline",
|
|
2554
|
+
children: "Try Studio"
|
|
2555
|
+
}, undefined, false, undefined, this)
|
|
2556
|
+
]
|
|
2557
|
+
}, undefined, true, undefined, this)
|
|
2558
|
+
]
|
|
2559
|
+
}, undefined, true, undefined, this)
|
|
2560
|
+
]
|
|
2561
|
+
}, undefined, true, undefined, this)
|
|
2562
|
+
}, undefined, false, undefined, this);
|
|
2563
|
+
}
|
|
2564
|
+
// src/components/templates/TemplateCommandDialog.tsx
|
|
2565
|
+
import {
|
|
2566
|
+
analyticsEventNames as analyticsEventNames2,
|
|
2567
|
+
captureAnalyticsEvent as captureAnalyticsEvent2
|
|
2568
|
+
} from "@contractspec/bundle.library/libs/posthog/client";
|
|
2569
|
+
import {
|
|
2570
|
+
Dialog as Dialog2,
|
|
2571
|
+
DialogContent as DialogContent2,
|
|
2572
|
+
DialogDescription as DialogDescription2,
|
|
2573
|
+
DialogHeader as DialogHeader2,
|
|
2574
|
+
DialogTitle as DialogTitle2
|
|
2575
|
+
} from "@contractspec/lib.ui-kit-web/ui/dialog";
|
|
2576
|
+
import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
|
|
2577
|
+
"use client";
|
|
2578
|
+
function TemplateCommandDialog({
|
|
2579
|
+
templateId,
|
|
2580
|
+
onClose,
|
|
2581
|
+
onDeployStudio
|
|
2582
|
+
}) {
|
|
2583
|
+
const command = templateId ? `npx contractspec init --template ${templateId}` : "";
|
|
2584
|
+
return /* @__PURE__ */ jsxDEV11(Dialog2, {
|
|
2585
|
+
open: !!templateId,
|
|
2586
|
+
onOpenChange: (open) => !open && onClose(),
|
|
2587
|
+
children: /* @__PURE__ */ jsxDEV11(DialogContent2, {
|
|
2588
|
+
className: "max-w-md",
|
|
2589
|
+
children: [
|
|
2590
|
+
/* @__PURE__ */ jsxDEV11(DialogHeader2, {
|
|
2591
|
+
children: [
|
|
2592
|
+
/* @__PURE__ */ jsxDEV11(DialogTitle2, {
|
|
2593
|
+
children: "Use this template"
|
|
2594
|
+
}, undefined, false, undefined, this),
|
|
2595
|
+
/* @__PURE__ */ jsxDEV11(DialogDescription2, {
|
|
2596
|
+
children: "Initialize a new project with this template using the CLI."
|
|
2597
|
+
}, undefined, false, undefined, this)
|
|
2598
|
+
]
|
|
2599
|
+
}, undefined, true, undefined, this),
|
|
2600
|
+
/* @__PURE__ */ jsxDEV11("div", {
|
|
2601
|
+
className: "space-y-4 pt-4",
|
|
2602
|
+
children: [
|
|
2603
|
+
/* @__PURE__ */ jsxDEV11("div", {
|
|
2604
|
+
className: "rounded-md border border-zinc-800 bg-zinc-950 p-4 font-mono text-sm text-zinc-50",
|
|
2605
|
+
children: command
|
|
2606
|
+
}, undefined, false, undefined, this),
|
|
2607
|
+
/* @__PURE__ */ jsxDEV11("div", {
|
|
2608
|
+
className: "flex gap-2",
|
|
2609
|
+
children: /* @__PURE__ */ jsxDEV11("button", {
|
|
2610
|
+
className: "btn-secondary w-full",
|
|
2611
|
+
onClick: () => {
|
|
2612
|
+
if (!templateId) {
|
|
2613
|
+
return;
|
|
2614
|
+
}
|
|
2615
|
+
navigator.clipboard.writeText(command);
|
|
2616
|
+
captureAnalyticsEvent2(analyticsEventNames2.COPY_COMMAND_CLICK, {
|
|
2617
|
+
surface: "templates",
|
|
2618
|
+
templateId,
|
|
2619
|
+
filename: "templates-cli"
|
|
2620
|
+
});
|
|
2621
|
+
},
|
|
2622
|
+
children: "Copy Command"
|
|
2623
|
+
}, undefined, false, undefined, this)
|
|
2624
|
+
}, undefined, false, undefined, this),
|
|
2625
|
+
/* @__PURE__ */ jsxDEV11("div", {
|
|
2626
|
+
className: "relative",
|
|
2627
|
+
children: [
|
|
2628
|
+
/* @__PURE__ */ jsxDEV11("div", {
|
|
2629
|
+
className: "absolute inset-0 flex items-center",
|
|
2630
|
+
children: /* @__PURE__ */ jsxDEV11("span", {
|
|
2631
|
+
className: "w-full border-border border-t"
|
|
2632
|
+
}, undefined, false, undefined, this)
|
|
2633
|
+
}, undefined, false, undefined, this),
|
|
2634
|
+
/* @__PURE__ */ jsxDEV11("div", {
|
|
2635
|
+
className: "relative flex justify-center text-xs uppercase",
|
|
2636
|
+
children: /* @__PURE__ */ jsxDEV11("span", {
|
|
2637
|
+
className: "bg-background px-2 text-muted-foreground",
|
|
2638
|
+
children: "Or"
|
|
2639
|
+
}, undefined, false, undefined, this)
|
|
2640
|
+
}, undefined, false, undefined, this)
|
|
2641
|
+
]
|
|
2642
|
+
}, undefined, true, undefined, this),
|
|
2643
|
+
/* @__PURE__ */ jsxDEV11("button", {
|
|
2644
|
+
className: "btn-ghost w-full text-sm",
|
|
2645
|
+
onClick: () => {
|
|
2646
|
+
if (!templateId) {
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2649
|
+
captureAnalyticsEvent2(analyticsEventNames2.CTA_STUDIO_CLICK, {
|
|
2650
|
+
surface: "templates",
|
|
2651
|
+
templateId
|
|
2652
|
+
});
|
|
2653
|
+
onDeployStudio();
|
|
2654
|
+
},
|
|
2655
|
+
children: "Deploy to Studio"
|
|
2656
|
+
}, undefined, false, undefined, this)
|
|
2657
|
+
]
|
|
2658
|
+
}, undefined, true, undefined, this)
|
|
2659
|
+
]
|
|
2660
|
+
}, undefined, true, undefined, this)
|
|
2661
|
+
}, undefined, false, undefined, this);
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
// src/components/templates/TemplatePreviewContent.tsx
|
|
2665
|
+
import {
|
|
2666
|
+
TemplateShell
|
|
2667
|
+
} from "@contractspec/lib.example-shared-ui";
|
|
2668
|
+
import { LoadingSpinner } from "@contractspec/lib.ui-kit-web/ui/atoms/LoadingSpinner";
|
|
2669
|
+
import dynamic from "next/dynamic";
|
|
2670
|
+
import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
|
|
2671
|
+
"use client";
|
|
2672
|
+
var SaasDashboard = dynamic(() => import("@contractspec/example.saas-boilerplate").then((module) => module.SaasDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2673
|
+
var CrmDashboard = dynamic(() => import("@contractspec/example.crm-pipeline").then((module) => module.CrmDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2674
|
+
var DataGridShowcase = dynamic(() => import("@contractspec/example.data-grid-showcase/ui").then((module) => module.DataGridShowcase), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2675
|
+
var VisualizationShowcase = dynamic(() => import("@contractspec/example.visualization-showcase/ui").then((module) => module.VisualizationShowcase), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2676
|
+
var AgentDashboard = dynamic(() => import("@contractspec/example.agent-console/ui").then((module) => module.AgentDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2677
|
+
var AiChatAssistantDashboard = dynamic(() => import("@contractspec/example.ai-chat-assistant").then((module) => module.AiChatAssistantDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2678
|
+
var WorkflowDashboard = dynamic(() => import("@contractspec/example.workflow-system/ui").then((module) => module.WorkflowDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2679
|
+
var MarketplaceDashboard = dynamic(() => import("@contractspec/example.marketplace/ui").then((module) => module.MarketplaceDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2680
|
+
var IntegrationDashboard = dynamic(() => import("@contractspec/example.integration-hub/ui").then((module) => module.IntegrationDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2681
|
+
var AnalyticsDashboard = dynamic(() => import("@contractspec/example.analytics-dashboard").then((module) => module.AnalyticsDashboard), { ssr: false, loading: () => /* @__PURE__ */ jsxDEV12(LoadingSpinner, {}, undefined, false, undefined, this) });
|
|
2682
|
+
var PREVIEW_DEFINITIONS = {
|
|
2683
|
+
"saas-boilerplate": {
|
|
2684
|
+
title: "SaaS Boilerplate",
|
|
2685
|
+
description: "Multi-tenant organizations, projects, settings, and billing usage tracking.",
|
|
2686
|
+
component: SaasDashboard
|
|
2687
|
+
},
|
|
2688
|
+
"crm-pipeline": {
|
|
2689
|
+
title: "CRM Pipeline",
|
|
2690
|
+
description: "Sales CRM with contacts, companies, deals, and pipeline stages.",
|
|
2691
|
+
component: CrmDashboard
|
|
2692
|
+
},
|
|
2693
|
+
"data-grid-showcase": {
|
|
2694
|
+
title: "Data Grid Showcase",
|
|
2695
|
+
description: "Shared ContractSpec table primitives with client, server, and DataView-driven lanes.",
|
|
2696
|
+
component: DataGridShowcase
|
|
2697
|
+
},
|
|
2698
|
+
"visualization-showcase": {
|
|
2699
|
+
title: "Visualization Showcase",
|
|
2700
|
+
description: "ContractSpec-owned chart primitives rendered through shared visualization contracts and design-system wrappers.",
|
|
2701
|
+
component: VisualizationShowcase
|
|
2702
|
+
},
|
|
2703
|
+
"agent-console": {
|
|
2704
|
+
title: "AI Agent Console",
|
|
2705
|
+
description: "AI agent orchestration with tools, agents, runs, and execution logs.",
|
|
2706
|
+
component: AgentDashboard
|
|
2707
|
+
},
|
|
2708
|
+
"ai-chat-assistant": {
|
|
2709
|
+
title: "AI Chat Assistant",
|
|
2710
|
+
description: "Focused assistant surface with reasoning, sources, suggestions, and MCP-aware tools.",
|
|
2711
|
+
component: AiChatAssistantDashboard
|
|
2712
|
+
},
|
|
2713
|
+
"workflow-system": {
|
|
2714
|
+
title: "Workflow System",
|
|
2715
|
+
description: "Multi-step workflows with role-based approvals.",
|
|
2716
|
+
component: WorkflowDashboard
|
|
2717
|
+
},
|
|
2718
|
+
marketplace: {
|
|
2719
|
+
title: "Marketplace",
|
|
2720
|
+
description: "Two-sided marketplace with stores, products, orders, and payouts.",
|
|
2721
|
+
component: MarketplaceDashboard
|
|
2722
|
+
},
|
|
2723
|
+
"integration-hub": {
|
|
2724
|
+
title: "Integration Hub",
|
|
2725
|
+
description: "Third-party integrations with connections, sync configs, and field mapping.",
|
|
2726
|
+
component: IntegrationDashboard
|
|
2727
|
+
},
|
|
2728
|
+
"analytics-dashboard": {
|
|
2729
|
+
title: "Analytics Dashboard",
|
|
2730
|
+
description: "Custom dashboards with widgets and queries.",
|
|
2731
|
+
component: AnalyticsDashboard
|
|
2732
|
+
}
|
|
2733
|
+
};
|
|
2734
|
+
function TemplatePreviewContent({
|
|
2735
|
+
templateId
|
|
2736
|
+
}) {
|
|
2737
|
+
const preview = PREVIEW_DEFINITIONS[templateId];
|
|
2738
|
+
if (!preview) {
|
|
2739
|
+
return null;
|
|
2740
|
+
}
|
|
2741
|
+
const PreviewComponent = preview.component;
|
|
2742
|
+
return /* @__PURE__ */ jsxDEV12(TemplateShell, {
|
|
2743
|
+
title: preview.title,
|
|
2744
|
+
description: preview.description,
|
|
2745
|
+
showSaveAction: false,
|
|
2746
|
+
children: /* @__PURE__ */ jsxDEV12(PreviewComponent, {}, undefined, false, undefined, this)
|
|
2747
|
+
}, undefined, false, undefined, this);
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
// src/components/templates/template-preview.ts
|
|
2751
|
+
var INLINE_TEMPLATE_PREVIEW_IDS = [
|
|
2752
|
+
"agent-console",
|
|
2753
|
+
"ai-chat-assistant",
|
|
2754
|
+
"analytics-dashboard",
|
|
2755
|
+
"crm-pipeline",
|
|
2756
|
+
"data-grid-showcase",
|
|
2757
|
+
"integration-hub",
|
|
2758
|
+
"marketplace",
|
|
2759
|
+
"saas-boilerplate",
|
|
2760
|
+
"visualization-showcase",
|
|
2761
|
+
"workflow-system"
|
|
2762
|
+
];
|
|
2763
|
+
var INLINE_TEMPLATE_PREVIEW_SET = new Set(INLINE_TEMPLATE_PREVIEW_IDS);
|
|
2764
|
+
function supportsInlineTemplatePreview(templateId) {
|
|
2765
|
+
return INLINE_TEMPLATE_PREVIEW_SET.has(templateId);
|
|
2766
|
+
}
|
|
2767
|
+
function getLocalTemplatePreviewAction(template) {
|
|
2768
|
+
if (supportsInlineTemplatePreview(template.id)) {
|
|
2769
|
+
return { kind: "modal", templateId: template.id };
|
|
2770
|
+
}
|
|
2771
|
+
return { kind: "sandbox", href: template.previewUrl };
|
|
2772
|
+
}
|
|
2773
|
+
function getRegistryTemplatePreviewAction(template, localTemplate) {
|
|
2774
|
+
if (!localTemplate) {
|
|
2775
|
+
return { kind: "disabled" };
|
|
2776
|
+
}
|
|
2777
|
+
return getLocalTemplatePreviewAction(localTemplate);
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
// src/components/templates/TemplatesPreviewModal.tsx
|
|
2781
|
+
import { Dialog as Dialog3, DialogContent as DialogContent3 } from "@contractspec/lib.ui-kit-web/ui/dialog";
|
|
2782
|
+
import { ScrollArea } from "@contractspec/lib.ui-kit-web/ui/scroll-area";
|
|
2783
|
+
import { TemplateRuntimeProvider } from "@contractspec/module.examples";
|
|
2784
|
+
import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
|
|
2785
|
+
"use client";
|
|
2786
|
+
function TemplatePreviewModal({
|
|
2787
|
+
templateId,
|
|
2788
|
+
onClose
|
|
2789
|
+
}) {
|
|
2790
|
+
if (!supportsInlineTemplatePreview(templateId)) {
|
|
2791
|
+
return null;
|
|
2792
|
+
}
|
|
2793
|
+
return /* @__PURE__ */ jsxDEV13(Dialog3, {
|
|
2794
|
+
open: true,
|
|
2795
|
+
onOpenChange: (open) => !open && onClose(),
|
|
2796
|
+
children: /* @__PURE__ */ jsxDEV13(DialogContent3, {
|
|
2797
|
+
className: "mb-8 flex h-[calc(100vh-2rem)] min-w-[calc(100vw-2rem)] flex-col justify-between gap-0 p-0",
|
|
2798
|
+
children: /* @__PURE__ */ jsxDEV13(ScrollArea, {
|
|
2799
|
+
className: "flex flex-col justify-between overflow-hidden",
|
|
2800
|
+
children: /* @__PURE__ */ jsxDEV13(TemplateRuntimeProvider, {
|
|
2801
|
+
templateId,
|
|
2802
|
+
projectId: `marketing-preview-${templateId}`,
|
|
2803
|
+
children: /* @__PURE__ */ jsxDEV13(TemplatePreviewContent, {
|
|
2804
|
+
templateId
|
|
2805
|
+
}, undefined, false, undefined, this)
|
|
2806
|
+
}, templateId, false, undefined, this)
|
|
2807
|
+
}, undefined, false, undefined, this)
|
|
2808
|
+
}, undefined, false, undefined, this)
|
|
2809
|
+
}, undefined, false, undefined, this);
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
// src/components/templates/TemplatesOverlays.tsx
|
|
2813
|
+
import {
|
|
2814
|
+
Dialog as Dialog4,
|
|
2815
|
+
DialogContent as DialogContent4,
|
|
2816
|
+
DialogDescription as DialogDescription3,
|
|
2817
|
+
DialogHeader as DialogHeader3,
|
|
2818
|
+
DialogTitle as DialogTitle3
|
|
2819
|
+
} from "@contractspec/lib.ui-kit-web/ui/dialog";
|
|
2820
|
+
import { jsxDEV as jsxDEV14, Fragment } from "react/jsx-dev-runtime";
|
|
2821
|
+
"use client";
|
|
2822
|
+
function TemplatesOverlays({
|
|
2823
|
+
previewTemplateId,
|
|
2824
|
+
onPreviewClose,
|
|
2825
|
+
studioSignupModalOpen,
|
|
2826
|
+
onStudioSignupModalOpenChange,
|
|
2827
|
+
selectedTemplateId,
|
|
2828
|
+
onTemplateCommandClose,
|
|
2829
|
+
onDeployStudio
|
|
2830
|
+
}) {
|
|
2831
|
+
return /* @__PURE__ */ jsxDEV14(Fragment, {
|
|
2832
|
+
children: [
|
|
2833
|
+
previewTemplateId ? /* @__PURE__ */ jsxDEV14(TemplatePreviewModal, {
|
|
2834
|
+
templateId: previewTemplateId,
|
|
2835
|
+
onClose: onPreviewClose
|
|
2836
|
+
}, undefined, false, undefined, this) : null,
|
|
2837
|
+
/* @__PURE__ */ jsxDEV14(Dialog4, {
|
|
2838
|
+
open: studioSignupModalOpen,
|
|
2839
|
+
onOpenChange: onStudioSignupModalOpenChange,
|
|
2840
|
+
children: /* @__PURE__ */ jsxDEV14(DialogContent4, {
|
|
2841
|
+
className: "max-h-[90vh] max-w-2xl overflow-y-auto",
|
|
2842
|
+
children: [
|
|
2843
|
+
/* @__PURE__ */ jsxDEV14(DialogHeader3, {
|
|
2844
|
+
children: [
|
|
2845
|
+
/* @__PURE__ */ jsxDEV14(DialogTitle3, {
|
|
2846
|
+
children: "Deploy in Studio"
|
|
2847
|
+
}, undefined, false, undefined, this),
|
|
2848
|
+
/* @__PURE__ */ jsxDEV14(DialogDescription3, {
|
|
2849
|
+
children: "Deploy templates in ContractSpec Studio and run the full evidence-to-spec loop with your team."
|
|
2850
|
+
}, undefined, false, undefined, this)
|
|
2851
|
+
]
|
|
2852
|
+
}, undefined, true, undefined, this),
|
|
2853
|
+
/* @__PURE__ */ jsxDEV14(StudioSignupSection, {
|
|
2854
|
+
variant: "compact"
|
|
2855
|
+
}, undefined, false, undefined, this)
|
|
2856
|
+
]
|
|
2857
|
+
}, undefined, true, undefined, this)
|
|
2858
|
+
}, undefined, false, undefined, this),
|
|
2859
|
+
/* @__PURE__ */ jsxDEV14(TemplateCommandDialog, {
|
|
2860
|
+
templateId: selectedTemplateId,
|
|
2861
|
+
onClose: onTemplateCommandClose,
|
|
2862
|
+
onDeployStudio
|
|
2863
|
+
}, undefined, false, undefined, this)
|
|
2864
|
+
]
|
|
2865
|
+
}, undefined, true, undefined, this);
|
|
2866
|
+
}
|
|
2867
|
+
export {
|
|
2868
|
+
TemplatesOverlays
|
|
2869
|
+
};
|