@contractspec/bundle.marketing 1.12.0 → 1.14.0
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 +146 -175
- package/.turbo/turbo-prebuild.log +1 -0
- package/CHANGELOG.md +57 -0
- package/dist/browser/components/marketing/ChangelogPage.js +92 -0
- package/dist/browser/components/marketing/CofounderPage.js +581 -0
- package/dist/browser/components/marketing/ContactClient.js +1379 -0
- package/dist/browser/components/marketing/ContributePage.js +487 -0
- package/dist/browser/components/marketing/DesignPartnerPage.js +272 -0
- package/dist/browser/components/marketing/LandingPage.js +629 -0
- package/dist/browser/components/marketing/PricingClient.js +1972 -0
- package/dist/browser/components/marketing/ProductClientPage.js +563 -0
- package/dist/browser/components/marketing/index.js +4818 -0
- package/dist/browser/components/marketing/pricing-thinking-modal.js +258 -0
- package/dist/browser/components/marketing/sections/AudienceSection.js +90 -0
- package/dist/browser/components/marketing/sections/CorePositioningSection.js +72 -0
- package/dist/browser/components/marketing/sections/CtaSection.js +67 -0
- package/dist/browser/components/marketing/sections/DevelopersSection.js +50 -0
- package/dist/browser/components/marketing/sections/FearsSection.js +105 -0
- package/dist/browser/components/marketing/sections/HeroMarketingSection.js +93 -0
- package/dist/browser/components/marketing/sections/IconGridSection.js +63 -0
- package/dist/browser/components/marketing/sections/OutputsSection.js +116 -0
- package/dist/browser/components/marketing/sections/ProblemSection.js +103 -0
- package/dist/browser/components/marketing/sections/SolutionSection.js +103 -0
- package/dist/browser/components/marketing/sections/StepsSection.js +109 -0
- package/dist/browser/components/marketing/waitlist-section.js +1104 -0
- package/dist/browser/components/templates/TemplatesClientPage.js +5662 -0
- package/dist/browser/components/templates/TemplatesPage.js +177 -0
- package/dist/browser/components/templates/TemplatesPreviewModal.js +124 -0
- package/dist/browser/components/templates/index.js +5831 -0
- package/dist/browser/index.js +6485 -0
- package/dist/browser/libs/email/client.js +122 -0
- package/dist/browser/libs/email/contact.js +190 -0
- package/dist/browser/libs/email/newsletter.js +215 -0
- package/dist/browser/libs/email/types.js +2 -0
- package/dist/browser/libs/email/utils.js +16 -0
- package/dist/browser/libs/email/waitlist-application.js +295 -0
- package/dist/browser/libs/email/waitlist.js +225 -0
- package/dist/browser/libs/pricing-examples.js +26 -0
- package/dist/browser/registry/engine.js +5293 -0
- package/dist/browser/registry/factory.js +52 -0
- package/dist/browser/registry/index.js +5358 -0
- package/dist/browser/registry/registry-docs.js +343 -0
- package/dist/browser/registry/registry-landing.js +4937 -0
- package/dist/browser/registry/registry.js +5279 -0
- package/dist/browser/registry/types.js +0 -0
- package/dist/browser/registry/utils.js +5340 -0
- package/dist/components/marketing/ChangelogPage.d.ts +11 -17
- package/dist/components/marketing/ChangelogPage.d.ts.map +1 -1
- package/dist/components/marketing/ChangelogPage.js +84 -62
- package/dist/components/marketing/CofounderPage.d.ts +1 -6
- package/dist/components/marketing/CofounderPage.d.ts.map +1 -1
- package/dist/components/marketing/CofounderPage.js +544 -436
- package/dist/components/marketing/ContactClient.d.ts +1 -6
- package/dist/components/marketing/ContactClient.d.ts.map +1 -1
- package/dist/components/marketing/ContactClient.js +1371 -155
- package/dist/components/marketing/ContributePage.d.ts +3 -8
- package/dist/components/marketing/ContributePage.d.ts.map +1 -1
- package/dist/components/marketing/ContributePage.js +478 -358
- package/dist/components/marketing/DesignPartnerPage.d.ts +3 -8
- package/dist/components/marketing/DesignPartnerPage.d.ts.map +1 -1
- package/dist/components/marketing/DesignPartnerPage.js +263 -211
- package/dist/components/marketing/LandingPage.d.ts +1 -6
- package/dist/components/marketing/LandingPage.d.ts.map +1 -1
- package/dist/components/marketing/LandingPage.js +623 -37
- package/dist/components/marketing/PricingClient.d.ts +1 -6
- package/dist/components/marketing/PricingClient.d.ts.map +1 -1
- package/dist/components/marketing/PricingClient.js +1962 -516
- package/dist/components/marketing/ProductClientPage.d.ts +1 -6
- package/dist/components/marketing/ProductClientPage.d.ts.map +1 -1
- package/dist/components/marketing/ProductClientPage.js +556 -458
- package/dist/components/marketing/index.d.ts +11 -11
- package/dist/components/marketing/index.d.ts.map +1 -0
- package/dist/components/marketing/index.js +4813 -12
- package/dist/components/marketing/pricing-thinking-modal.d.ts +5 -13
- package/dist/components/marketing/pricing-thinking-modal.d.ts.map +1 -1
- package/dist/components/marketing/pricing-thinking-modal.js +248 -197
- package/dist/components/marketing/sections/AudienceSection.d.ts +1 -6
- package/dist/components/marketing/sections/AudienceSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/AudienceSection.js +80 -63
- package/dist/components/marketing/sections/CorePositioningSection.d.ts +1 -6
- package/dist/components/marketing/sections/CorePositioningSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/CorePositioningSection.js +62 -54
- package/dist/components/marketing/sections/CtaSection.d.ts +1 -6
- package/dist/components/marketing/sections/CtaSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/CtaSection.js +58 -50
- package/dist/components/marketing/sections/DevelopersSection.d.ts +1 -6
- package/dist/components/marketing/sections/DevelopersSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/DevelopersSection.js +40 -40
- package/dist/components/marketing/sections/FearsSection.d.ts +1 -6
- package/dist/components/marketing/sections/FearsSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/FearsSection.js +96 -44
- package/dist/components/marketing/sections/HeroMarketingSection.d.ts +1 -6
- package/dist/components/marketing/sections/HeroMarketingSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/HeroMarketingSection.js +82 -71
- package/dist/components/marketing/sections/IconGridSection.d.ts +25 -39
- package/dist/components/marketing/sections/IconGridSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/IconGridSection.js +55 -41
- package/dist/components/marketing/sections/OutputsSection.d.ts +1 -6
- package/dist/components/marketing/sections/OutputsSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/OutputsSection.js +107 -55
- package/dist/components/marketing/sections/ProblemSection.d.ts +1 -6
- package/dist/components/marketing/sections/ProblemSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/ProblemSection.js +94 -42
- package/dist/components/marketing/sections/SolutionSection.d.ts +1 -6
- package/dist/components/marketing/sections/SolutionSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/SolutionSection.js +94 -42
- package/dist/components/marketing/sections/StepsSection.d.ts +1 -6
- package/dist/components/marketing/sections/StepsSection.d.ts.map +1 -1
- package/dist/components/marketing/sections/StepsSection.js +100 -48
- package/dist/components/marketing/waitlist-section.d.ts +5 -12
- package/dist/components/marketing/waitlist-section.d.ts.map +1 -1
- package/dist/components/marketing/waitlist-section.js +1089 -568
- package/dist/components/templates/TemplatesClientPage.d.ts +1 -6
- package/dist/components/templates/TemplatesClientPage.d.ts.map +1 -1
- package/dist/components/templates/TemplatesClientPage.js +5649 -617
- package/dist/components/templates/TemplatesPage.d.ts +1 -6
- package/dist/components/templates/TemplatesPage.d.ts.map +1 -1
- package/dist/components/templates/TemplatesPage.js +163 -116
- package/dist/components/templates/TemplatesPreviewModal.d.ts +5 -12
- package/dist/components/templates/TemplatesPreviewModal.d.ts.map +1 -1
- package/dist/components/templates/TemplatesPreviewModal.js +113 -131
- package/dist/components/templates/index.d.ts +4 -4
- package/dist/components/templates/index.d.ts.map +1 -0
- package/dist/components/templates/index.js +5825 -4
- package/dist/index.d.ts +9 -29
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6480 -28
- package/dist/libs/email/client.d.ts +9 -12
- package/dist/libs/email/client.d.ts.map +1 -1
- package/dist/libs/email/client.js +109 -105
- package/dist/libs/email/client.test.d.ts +2 -0
- package/dist/libs/email/client.test.d.ts.map +1 -0
- package/dist/libs/email/contact.d.ts +2 -6
- package/dist/libs/email/contact.d.ts.map +1 -1
- package/dist/libs/email/contact.js +155 -41
- package/dist/libs/email/newsletter.d.ts +2 -6
- package/dist/libs/email/newsletter.d.ts.map +1 -1
- package/dist/libs/email/newsletter.js +169 -54
- package/dist/libs/email/types.d.ts +48 -52
- package/dist/libs/email/types.d.ts.map +1 -1
- package/dist/libs/email/types.js +3 -1
- package/dist/libs/email/utils.d.ts +2 -5
- package/dist/libs/email/utils.d.ts.map +1 -1
- package/dist/libs/email/utils.js +10 -6
- package/dist/libs/email/waitlist-application.d.ts +2 -6
- package/dist/libs/email/waitlist-application.d.ts.map +1 -1
- package/dist/libs/email/waitlist-application.js +191 -71
- package/dist/libs/email/waitlist.d.ts +2 -6
- package/dist/libs/email/waitlist.d.ts.map +1 -1
- package/dist/libs/email/waitlist.js +171 -56
- package/dist/libs/pricing-examples.d.ts +13 -16
- package/dist/libs/pricing-examples.d.ts.map +1 -1
- package/dist/libs/pricing-examples.js +20 -20
- package/dist/node/components/marketing/ChangelogPage.js +87 -0
- package/dist/node/components/marketing/CofounderPage.js +576 -0
- package/dist/node/components/marketing/ContactClient.js +1374 -0
- package/dist/node/components/marketing/ContributePage.js +482 -0
- package/dist/node/components/marketing/DesignPartnerPage.js +267 -0
- package/dist/node/components/marketing/LandingPage.js +624 -0
- package/dist/node/components/marketing/PricingClient.js +1967 -0
- package/dist/node/components/marketing/ProductClientPage.js +558 -0
- package/dist/node/components/marketing/index.js +4813 -0
- package/dist/node/components/marketing/pricing-thinking-modal.js +253 -0
- package/dist/node/components/marketing/sections/AudienceSection.js +85 -0
- package/dist/node/components/marketing/sections/CorePositioningSection.js +67 -0
- package/dist/node/components/marketing/sections/CtaSection.js +62 -0
- package/dist/node/components/marketing/sections/DevelopersSection.js +45 -0
- package/dist/node/components/marketing/sections/FearsSection.js +100 -0
- package/dist/node/components/marketing/sections/HeroMarketingSection.js +88 -0
- package/dist/node/components/marketing/sections/IconGridSection.js +58 -0
- package/dist/node/components/marketing/sections/OutputsSection.js +111 -0
- package/dist/node/components/marketing/sections/ProblemSection.js +98 -0
- package/dist/node/components/marketing/sections/SolutionSection.js +98 -0
- package/dist/node/components/marketing/sections/StepsSection.js +104 -0
- package/dist/node/components/marketing/waitlist-section.js +1099 -0
- package/dist/node/components/templates/TemplatesClientPage.js +5657 -0
- package/dist/node/components/templates/TemplatesPage.js +172 -0
- package/dist/node/components/templates/TemplatesPreviewModal.js +119 -0
- package/dist/node/components/templates/index.js +5826 -0
- package/dist/node/index.js +6480 -0
- package/dist/node/libs/email/client.js +117 -0
- package/dist/node/libs/email/contact.js +185 -0
- package/dist/node/libs/email/newsletter.js +210 -0
- package/dist/node/libs/email/types.js +2 -0
- package/dist/node/libs/email/utils.js +11 -0
- package/dist/node/libs/email/waitlist-application.js +290 -0
- package/dist/node/libs/email/waitlist.js +220 -0
- package/dist/node/libs/pricing-examples.js +21 -0
- package/dist/node/registry/engine.js +5288 -0
- package/dist/node/registry/factory.js +47 -0
- package/dist/node/registry/index.js +5353 -0
- package/dist/node/registry/registry-docs.js +338 -0
- package/dist/node/registry/registry-landing.js +4932 -0
- package/dist/node/registry/registry.js +5274 -0
- package/dist/node/registry/types.js +0 -0
- package/dist/node/registry/utils.js +5335 -0
- package/dist/registry/engine.d.ts +4 -8
- package/dist/registry/engine.d.ts.map +1 -1
- package/dist/registry/engine.js +5287 -23
- package/dist/registry/factory.d.ts +30 -34
- package/dist/registry/factory.d.ts.map +1 -1
- package/dist/registry/factory.js +42 -56
- package/dist/registry/index.d.ts +8 -8
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +5353 -8
- package/dist/registry/registry-docs.d.ts +4 -8
- package/dist/registry/registry-docs.d.ts.map +1 -1
- package/dist/registry/registry-docs.js +242 -209
- package/dist/registry/registry-landing.d.ts +5 -9
- package/dist/registry/registry-landing.d.ts.map +1 -1
- package/dist/registry/registry-landing.js +4930 -93
- package/dist/registry/registry.d.ts +7 -11
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +5262 -49
- package/dist/registry/types.d.ts +6 -10
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/types.js +1 -0
- package/dist/registry/utils.d.ts +10 -14
- package/dist/registry/utils.d.ts.map +1 -1
- package/dist/registry/utils.js +5330 -49
- package/package.json +355 -73
- package/tsdown.config.js +1 -2
- package/.turbo/turbo-build$colon$types.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/dist/components/marketing/ChangelogPage.js.map +0 -1
- package/dist/components/marketing/CofounderPage.js.map +0 -1
- package/dist/components/marketing/ContactClient.js.map +0 -1
- package/dist/components/marketing/ContributePage.js.map +0 -1
- package/dist/components/marketing/DesignPartnerPage.js.map +0 -1
- package/dist/components/marketing/LandingPage.js.map +0 -1
- package/dist/components/marketing/PricingClient.js.map +0 -1
- package/dist/components/marketing/ProductClientPage.js.map +0 -1
- package/dist/components/marketing/pricing-thinking-modal.js.map +0 -1
- package/dist/components/marketing/sections/AudienceSection.js.map +0 -1
- package/dist/components/marketing/sections/CorePositioningSection.js.map +0 -1
- package/dist/components/marketing/sections/CtaSection.js.map +0 -1
- package/dist/components/marketing/sections/DevelopersSection.js.map +0 -1
- package/dist/components/marketing/sections/FearsSection.js.map +0 -1
- package/dist/components/marketing/sections/HeroMarketingSection.js.map +0 -1
- package/dist/components/marketing/sections/IconGridSection.js.map +0 -1
- package/dist/components/marketing/sections/OutputsSection.js.map +0 -1
- package/dist/components/marketing/sections/ProblemSection.js.map +0 -1
- package/dist/components/marketing/sections/SolutionSection.js.map +0 -1
- package/dist/components/marketing/sections/StepsSection.js.map +0 -1
- package/dist/components/marketing/waitlist-section.js.map +0 -1
- package/dist/components/templates/TemplatesClientPage.js.map +0 -1
- package/dist/components/templates/TemplatesPage.js.map +0 -1
- package/dist/components/templates/TemplatesPreviewModal.js.map +0 -1
- package/dist/libs/email/client.js.map +0 -1
- package/dist/libs/email/contact.js.map +0 -1
- package/dist/libs/email/newsletter.js.map +0 -1
- package/dist/libs/email/utils.js.map +0 -1
- package/dist/libs/email/waitlist-application.js.map +0 -1
- package/dist/libs/email/waitlist.js.map +0 -1
- package/dist/libs/pricing-examples.js.map +0 -1
- package/dist/registry/engine.js.map +0 -1
- package/dist/registry/factory.js.map +0 -1
- package/dist/registry/registry-docs.js.map +0 -1
- package/dist/registry/registry-landing.js.map +0 -1
- package/dist/registry/registry.js.map +0 -1
- package/dist/registry/utils.js.map +0 -1
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,1972 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined")
|
|
5
|
+
return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/libs/email/client.ts
|
|
10
|
+
import { createClient, Temv1alpha1 } from "@scaleway/sdk";
|
|
11
|
+
import { Logger } from "@contractspec/lib.logger";
|
|
12
|
+
var DEFAULT_FROM = {
|
|
13
|
+
email: "noreply@transactional.contractspec.io",
|
|
14
|
+
name: "ContractSpec"
|
|
15
|
+
};
|
|
16
|
+
var DEFAULT_TEAM_INBOX = {
|
|
17
|
+
email: "contact@contractspec.io",
|
|
18
|
+
name: "ContractSpec Team"
|
|
19
|
+
};
|
|
20
|
+
var DEFAULT_REGION = "fr-par";
|
|
21
|
+
var cachedConfig = null;
|
|
22
|
+
var cachedClient = null;
|
|
23
|
+
var apiFactory = (client) => new Temv1alpha1.API(client);
|
|
24
|
+
var mapRegion = (value) => {
|
|
25
|
+
const normalized = value?.trim().toLowerCase();
|
|
26
|
+
if (normalized === "par" || normalized === "fr-par")
|
|
27
|
+
return "fr-par";
|
|
28
|
+
if (normalized === "ams" || normalized === "nl-ams")
|
|
29
|
+
return "nl-ams";
|
|
30
|
+
if (normalized === "waw" || normalized === "pl-waw")
|
|
31
|
+
return "pl-waw";
|
|
32
|
+
return DEFAULT_REGION;
|
|
33
|
+
};
|
|
34
|
+
var getEmailConfig = () => {
|
|
35
|
+
if (cachedConfig) {
|
|
36
|
+
return { ok: true, config: cachedConfig };
|
|
37
|
+
}
|
|
38
|
+
const accessKey = process.env.SCALEWAY_ACCESS_KEY || process.env.SCALEWAY_ACCESS_KEY_QUEUE;
|
|
39
|
+
const secretKey = process.env.SCALEWAY_SECRET_KEY || process.env.SCALEWAY_SECRET_KEY_QUEUE;
|
|
40
|
+
const projectId = process.env.SCALEWAY_PROJECT_ID;
|
|
41
|
+
if (!accessKey || !secretKey || !projectId) {
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
errorMessage: "Email service is not configured. Please contact us directly at contact@contractspec.io."
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const region = mapRegion(process.env.SCALEWAY_REGION);
|
|
48
|
+
cachedConfig = {
|
|
49
|
+
accessKey,
|
|
50
|
+
secretKey,
|
|
51
|
+
projectId,
|
|
52
|
+
region,
|
|
53
|
+
defaultZone: `${region}-1`,
|
|
54
|
+
from: {
|
|
55
|
+
email: process.env.SCALEWAY_EMAIL_FROM_EMAIL ?? DEFAULT_FROM.email,
|
|
56
|
+
name: process.env.SCALEWAY_EMAIL_FROM_NAME ?? DEFAULT_FROM.name
|
|
57
|
+
},
|
|
58
|
+
teamInbox: {
|
|
59
|
+
email: process.env.SCALEWAY_EMAIL_TEAM_EMAIL ?? DEFAULT_TEAM_INBOX.email,
|
|
60
|
+
name: process.env.SCALEWAY_EMAIL_TEAM_NAME ?? DEFAULT_TEAM_INBOX.name
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
return { ok: true, config: cachedConfig };
|
|
64
|
+
};
|
|
65
|
+
var getTemClient = (config) => {
|
|
66
|
+
if (cachedClient) {
|
|
67
|
+
return cachedClient;
|
|
68
|
+
}
|
|
69
|
+
const client = createClient({
|
|
70
|
+
accessKey: config.accessKey,
|
|
71
|
+
secretKey: config.secretKey,
|
|
72
|
+
defaultProjectId: config.projectId,
|
|
73
|
+
defaultRegion: config.region,
|
|
74
|
+
defaultZone: config.defaultZone
|
|
75
|
+
});
|
|
76
|
+
cachedClient = apiFactory(client);
|
|
77
|
+
return cachedClient;
|
|
78
|
+
};
|
|
79
|
+
var sendEmail = async (config, request) => {
|
|
80
|
+
try {
|
|
81
|
+
const client = getTemClient(config);
|
|
82
|
+
await client.createEmail({
|
|
83
|
+
region: config.region,
|
|
84
|
+
projectId: config.projectId,
|
|
85
|
+
from: config.from,
|
|
86
|
+
to: request.to,
|
|
87
|
+
subject: request.subject,
|
|
88
|
+
text: request.text,
|
|
89
|
+
html: request.html || request.text,
|
|
90
|
+
additionalHeaders: request.replyTo ? [{ key: "Reply-To", value: request.replyTo }] : undefined
|
|
91
|
+
});
|
|
92
|
+
return { success: true };
|
|
93
|
+
} catch (error) {
|
|
94
|
+
new Logger().error("scaleway_tem_email_send_failed", {
|
|
95
|
+
context: request.context ?? "email",
|
|
96
|
+
error: error instanceof Error ? error.message : error
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
error,
|
|
101
|
+
errorMessage: "Failed to send email via Scaleway."
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var __internal = {
|
|
106
|
+
resetCaches() {
|
|
107
|
+
cachedClient = null;
|
|
108
|
+
cachedConfig = null;
|
|
109
|
+
apiFactory = (client) => new Temv1alpha1.API(client);
|
|
110
|
+
},
|
|
111
|
+
setApiFactory(factory) {
|
|
112
|
+
apiFactory = factory;
|
|
113
|
+
},
|
|
114
|
+
setClient(client) {
|
|
115
|
+
cachedClient = client;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/libs/email/utils.ts
|
|
120
|
+
var escapeHtml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
121
|
+
var formatMultilineHtml = (value) => escapeHtml(value).replaceAll(`
|
|
122
|
+
`, "<br />");
|
|
123
|
+
|
|
124
|
+
// src/libs/email/waitlist.ts
|
|
125
|
+
"use server";
|
|
126
|
+
var WAITLIST_MISSING_CONFIG = "Waitlist service is not configured. Please try again later.";
|
|
127
|
+
var WAITLIST_SEND_ERROR = "Failed to join waitlist. Please try again later or contact us directly.";
|
|
128
|
+
var joinWaitlist = async (formData) => {
|
|
129
|
+
const email = (formData.get("email") ?? "").toString().trim();
|
|
130
|
+
if (!email || !email.includes("@")) {
|
|
131
|
+
return {
|
|
132
|
+
success: false,
|
|
133
|
+
text: "Please enter a valid email address."
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const configResult = getEmailConfig();
|
|
137
|
+
if (!configResult.ok || !configResult.config) {
|
|
138
|
+
return {
|
|
139
|
+
success: false,
|
|
140
|
+
text: configResult.errorMessage ?? WAITLIST_MISSING_CONFIG
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const waitlistText = `
|
|
144
|
+
You're on the waitlist!
|
|
145
|
+
|
|
146
|
+
Thanks for joining the ContractSpec waitlist. You're now in line for early access to:
|
|
147
|
+
|
|
148
|
+
• Stabilize your AI-generated code with ContractSpec
|
|
149
|
+
• Multi-surface consistency (API, DB, UI, events)
|
|
150
|
+
• Safe regeneration without breaking changes
|
|
151
|
+
• AI governance and contract enforcement
|
|
152
|
+
|
|
153
|
+
We'll notify you as soon as early access is available. In the meantime, you can:
|
|
154
|
+
|
|
155
|
+
• Check out our docs: https://contractspec.io/docs
|
|
156
|
+
• Follow our progress on GitHub
|
|
157
|
+
• Book a demo call to see ContractSpec in action
|
|
158
|
+
|
|
159
|
+
We're excited to have you on board!
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
ContractSpec Team
|
|
163
|
+
https://contractspec.io
|
|
164
|
+
|
|
165
|
+
To remove yourself from the waitlist, reply to this email with "remove"
|
|
166
|
+
`.trim();
|
|
167
|
+
const waitlistHtml = `
|
|
168
|
+
<div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
|
|
169
|
+
<h1 style="color: #8b5cf6;">You're on the waitlist!</h1>
|
|
170
|
+
<p>Thanks for joining the ContractSpec waitlist. You're now in line for early access to:</p>
|
|
171
|
+
<ul style="line-height: 1.8;">
|
|
172
|
+
<li>Stabilize your AI-generated code with ContractSpec</li>
|
|
173
|
+
<li>Multi-surface consistency (API, DB, UI, events)</li>
|
|
174
|
+
<li>Safe regeneration without breaking changes</li>
|
|
175
|
+
<li>AI governance and contract enforcement</li>
|
|
176
|
+
</ul>
|
|
177
|
+
<p>We'll notify you as soon as early access is available. In the meantime, you can:</p>
|
|
178
|
+
<ul style="line-height: 1.8;">
|
|
179
|
+
<li>Check out our <a href="https://contractspec.io/docs" style="color: #8b5cf6;">docs</a></li>
|
|
180
|
+
<li>Follow our progress on GitHub</li>
|
|
181
|
+
<li>Book a demo call to see ContractSpec in action</li>
|
|
182
|
+
</ul>
|
|
183
|
+
<p>We're excited to have you on board!</p>
|
|
184
|
+
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;" />
|
|
185
|
+
<p style="color: #6b7280; font-size: 14px;">
|
|
186
|
+
ContractSpec Team<br />
|
|
187
|
+
<a href="https://contractspec.io" style="color: #8b5cf6;">contractspec.io</a>
|
|
188
|
+
</p>
|
|
189
|
+
<p style="color: #9ca3af; font-size: 12px;">
|
|
190
|
+
To remove yourself from the waitlist, reply to this email with "remove"
|
|
191
|
+
</p>
|
|
192
|
+
</div>
|
|
193
|
+
`;
|
|
194
|
+
const userSend = await sendEmail(configResult.config, {
|
|
195
|
+
to: [{ email }],
|
|
196
|
+
subject: "You're on the ContractSpec waitlist!",
|
|
197
|
+
text: waitlistText,
|
|
198
|
+
html: waitlistHtml,
|
|
199
|
+
context: "waitlist-welcome"
|
|
200
|
+
});
|
|
201
|
+
if (!userSend.success) {
|
|
202
|
+
return { success: false, text: WAITLIST_SEND_ERROR };
|
|
203
|
+
}
|
|
204
|
+
const teamNotificationText = `New waitlist signup from: ${email}`;
|
|
205
|
+
const teamNotificationHtml = `
|
|
206
|
+
<div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
|
|
207
|
+
<p style="margin: 0 0 8px;">New waitlist signup</p>
|
|
208
|
+
<p style="margin: 0;"><strong>Email:</strong> ${formatMultilineHtml(email)}</p>
|
|
209
|
+
</div>
|
|
210
|
+
`;
|
|
211
|
+
const teamSend = await sendEmail(configResult.config, {
|
|
212
|
+
to: [configResult.config.teamInbox],
|
|
213
|
+
subject: `New Waitlist Signup: ${email}`,
|
|
214
|
+
text: teamNotificationText,
|
|
215
|
+
html: teamNotificationHtml,
|
|
216
|
+
context: "waitlist-team-notification"
|
|
217
|
+
});
|
|
218
|
+
if (!teamSend.success) {
|
|
219
|
+
return { success: false, text: WAITLIST_SEND_ERROR };
|
|
220
|
+
}
|
|
221
|
+
return { success: true, text: "Successfully joined waitlist!" };
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// src/libs/email/waitlist-application.ts
|
|
225
|
+
"use server";
|
|
226
|
+
var APPLICATION_MISSING_CONFIG = "Waitlist application service is not configured. Please try again later.";
|
|
227
|
+
var APPLICATION_SEND_ERROR = "Failed to submit application. Please try again later or contact us directly.";
|
|
228
|
+
var submitWaitlistApplication = async (formData) => {
|
|
229
|
+
const email = (formData.get("email") ?? "").toString().trim();
|
|
230
|
+
const name = (formData.get("name") ?? "").toString().trim();
|
|
231
|
+
const company = (formData.get("company") ?? "").toString().trim();
|
|
232
|
+
const role = (formData.get("role") ?? "").toString().trim();
|
|
233
|
+
const useCase = (formData.get("useCase") ?? "").toString().trim();
|
|
234
|
+
const currentStack = (formData.get("currentStack") ?? "").toString().trim();
|
|
235
|
+
const whatBuilding = (formData.get("whatBuilding") ?? "").toString().trim();
|
|
236
|
+
const whatSolving = (formData.get("whatSolving") ?? "").toString().trim();
|
|
237
|
+
const teamSize = (formData.get("teamSize") ?? "").toString().trim();
|
|
238
|
+
const timeline = (formData.get("timeline") ?? "").toString().trim();
|
|
239
|
+
const openToSessions = formData.get("openToSessions") === "on";
|
|
240
|
+
const okayWithCaseStudies = formData.get("okayWithCaseStudies") === "on";
|
|
241
|
+
if (!email || !email.includes("@")) {
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
text: "Please enter a valid email address."
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (!name || !whatBuilding || !whatSolving) {
|
|
248
|
+
return {
|
|
249
|
+
success: false,
|
|
250
|
+
text: "Please fill in all required fields."
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const configResult = getEmailConfig();
|
|
254
|
+
if (!configResult.ok || !configResult.config) {
|
|
255
|
+
return {
|
|
256
|
+
success: false,
|
|
257
|
+
text: configResult.errorMessage ?? APPLICATION_MISSING_CONFIG
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const applicantText = `
|
|
261
|
+
You're on the list.
|
|
262
|
+
|
|
263
|
+
Thanks for applying to the ContractSpec design partner program. We're slowly onboarding design partners in waves. If your use case is a good fit, we'll reach out personally.
|
|
264
|
+
|
|
265
|
+
What happens next:
|
|
266
|
+
• We review applications weekly
|
|
267
|
+
• If selected, we'll reach out via email to schedule an intro call
|
|
268
|
+
• During early access, you'll get hands-on support and influence over the roadmap
|
|
269
|
+
|
|
270
|
+
In the meantime:
|
|
271
|
+
• Check out our docs: https://contractspec.io/docs
|
|
272
|
+
• Book a demo call: https://contractspec.io/contact
|
|
273
|
+
|
|
274
|
+
We're excited about the possibility of working together!
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
ContractSpec Team
|
|
278
|
+
https://contractspec.io
|
|
279
|
+
`.trim();
|
|
280
|
+
const applicantHtml = `
|
|
281
|
+
<div style="font-family: sans-serif; max-width: 640px; margin: 0 auto;">
|
|
282
|
+
<h1 style="color: #8b5cf6;">You're on the list.</h1>
|
|
283
|
+
<p>Thanks for applying to the ContractSpec design partner program. We're slowly onboarding design partners in waves. If your use case is a good fit, we'll reach out personally.</p>
|
|
284
|
+
<h2 style="color: #8b5cf6; margin-top: 24px;">What happens next:</h2>
|
|
285
|
+
<ul style="line-height: 1.8;">
|
|
286
|
+
<li>We review applications weekly</li>
|
|
287
|
+
<li>If selected, we'll reach out via email to schedule an intro call</li>
|
|
288
|
+
<li>During early access, you'll get hands-on support and influence over the roadmap</li>
|
|
289
|
+
</ul>
|
|
290
|
+
<h2 style="color: #8b5cf6; margin-top: 24px;">In the meantime:</h2>
|
|
291
|
+
<ul style="line-height: 1.8;">
|
|
292
|
+
<li>Check out our <a href="https://contractspec.io/docs" style="color: #8b5cf6;">docs</a></li>
|
|
293
|
+
<li>Book a demo call: <a href="https://contractspec.io/contact" style="color: #8b5cf6;">contractspec.io/contact</a></li>
|
|
294
|
+
</ul>
|
|
295
|
+
<p>We're excited about the possibility of working together!</p>
|
|
296
|
+
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;" />
|
|
297
|
+
<p style="color: #6b7280; font-size: 14px;">
|
|
298
|
+
ContractSpec Team<br />
|
|
299
|
+
<a href="https://contractspec.io" style="color: #8b5cf6;">contractspec.io</a>
|
|
300
|
+
</p>
|
|
301
|
+
</div>
|
|
302
|
+
`;
|
|
303
|
+
const applicantSend = await sendEmail(configResult.config, {
|
|
304
|
+
to: [{ email }],
|
|
305
|
+
subject: "You're on the ContractSpec design partner waitlist!",
|
|
306
|
+
text: applicantText,
|
|
307
|
+
html: applicantHtml,
|
|
308
|
+
context: "waitlist-application-welcome"
|
|
309
|
+
});
|
|
310
|
+
if (!applicantSend.success) {
|
|
311
|
+
return { success: false, text: APPLICATION_SEND_ERROR };
|
|
312
|
+
}
|
|
313
|
+
const preferencesText = `
|
|
314
|
+
Open to 1:1 product/design sessions: ${openToSessions ? "Yes" : "No"}
|
|
315
|
+
Okay with anonymized case studies: ${okayWithCaseStudies ? "Yes" : "No"}
|
|
316
|
+
`.trim();
|
|
317
|
+
const teamEmailText = `
|
|
318
|
+
New Design Partner Waitlist Application
|
|
319
|
+
|
|
320
|
+
Contact Information:
|
|
321
|
+
- Name: ${name}
|
|
322
|
+
- Email: ${email}
|
|
323
|
+
${company ? `- Company/Project: ${company}` : ""}
|
|
324
|
+
${role ? `- Role: ${role}` : ""}
|
|
325
|
+
|
|
326
|
+
Application Details:
|
|
327
|
+
- What are you building with AI today?
|
|
328
|
+
${whatBuilding}
|
|
329
|
+
|
|
330
|
+
- What do you hope ContractSpec will solve for you?
|
|
331
|
+
${whatSolving}
|
|
332
|
+
|
|
333
|
+
- Primary use case: ${useCase || "Not specified"}
|
|
334
|
+
- Current stack: ${currentStack || "Not specified"}
|
|
335
|
+
- Team Size: ${teamSize || "Not specified"}
|
|
336
|
+
- Timeline: ${timeline || "Not specified"}
|
|
337
|
+
|
|
338
|
+
Preferences:
|
|
339
|
+
- Open to 1:1 product/design sessions: ${openToSessions ? "Yes" : "No"}
|
|
340
|
+
- Okay with anonymized case studies: ${okayWithCaseStudies ? "Yes" : "No"}
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
Submitted via ContractSpec waitlist application form
|
|
344
|
+
`.trim();
|
|
345
|
+
const teamEmailHtml = `
|
|
346
|
+
<div style="font-family: sans-serif; max-width: 720px; margin: 0 auto;">
|
|
347
|
+
<h1 style="color: #8b5cf6;">New Design Partner Waitlist Application</h1>
|
|
348
|
+
<h2 style="color: #8b5cf6; margin: 16px 0 8px;">Contact Information</h2>
|
|
349
|
+
<ul style="padding-left: 16px; line-height: 1.6; margin: 0 0 16px;">
|
|
350
|
+
<li>Name: ${escapeHtml(name)}</li>
|
|
351
|
+
<li>Email: ${escapeHtml(email)}</li>
|
|
352
|
+
${company ? `<li>Company/Project: ${escapeHtml(company)}</li>` : ""}
|
|
353
|
+
${role ? `<li>Role: ${escapeHtml(role)}</li>` : ""}
|
|
354
|
+
</ul>
|
|
355
|
+
<h2 style="color: #8b5cf6; margin: 16px 0 8px;">Application Details</h2>
|
|
356
|
+
<p style="margin: 0 0 8px; font-weight: 600;">What are you building with AI today?</p>
|
|
357
|
+
<div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;">
|
|
358
|
+
${formatMultilineHtml(whatBuilding)}
|
|
359
|
+
</div>
|
|
360
|
+
<p style="margin: 16px 0 8px; font-weight: 600;">What do you hope ContractSpec will solve for you?</p>
|
|
361
|
+
<div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; white-space: pre-wrap; line-height: 1.6;">
|
|
362
|
+
${formatMultilineHtml(whatSolving)}
|
|
363
|
+
</div>
|
|
364
|
+
<ul style="padding-left: 16px; line-height: 1.6; margin: 16px 0;">
|
|
365
|
+
<li>Primary use case: ${escapeHtml(useCase || "Not specified")}</li>
|
|
366
|
+
<li>Current stack: ${escapeHtml(currentStack || "Not specified")}</li>
|
|
367
|
+
<li>Team Size: ${escapeHtml(teamSize || "Not specified")}</li>
|
|
368
|
+
<li>Timeline: ${escapeHtml(timeline || "Not specified")}</li>
|
|
369
|
+
</ul>
|
|
370
|
+
<h2 style="color: #8b5cf6; margin: 16px 0 8px;">Preferences</h2>
|
|
371
|
+
<div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px; background: #f9fafb; line-height: 1.6;">
|
|
372
|
+
${formatMultilineHtml(preferencesText)}
|
|
373
|
+
</div>
|
|
374
|
+
<p style="color: #6b7280; font-size: 12px; margin-top: 20px;">Submitted via ContractSpec waitlist application form</p>
|
|
375
|
+
</div>
|
|
376
|
+
`;
|
|
377
|
+
const teamSend = await sendEmail(configResult.config, {
|
|
378
|
+
to: [configResult.config.teamInbox],
|
|
379
|
+
subject: `New Design Partner Application: ${name} (${email})`,
|
|
380
|
+
text: teamEmailText,
|
|
381
|
+
html: teamEmailHtml,
|
|
382
|
+
replyTo: email,
|
|
383
|
+
context: "waitlist-application-team-notification"
|
|
384
|
+
});
|
|
385
|
+
if (!teamSend.success) {
|
|
386
|
+
return { success: false, text: APPLICATION_SEND_ERROR };
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
success: true,
|
|
390
|
+
text: "Application submitted successfully!"
|
|
391
|
+
};
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// src/components/marketing/waitlist-section.tsx
|
|
395
|
+
import { useEffect, useState } from "react";
|
|
396
|
+
import { useForm } from "react-hook-form";
|
|
397
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
398
|
+
import z from "zod";
|
|
399
|
+
import { AlertCircle, CheckCircle } from "lucide-react";
|
|
400
|
+
import { Button } from "@contractspec/lib.design-system";
|
|
401
|
+
import { Textarea } from "@contractspec/lib.design-system";
|
|
402
|
+
import { Label } from "@contractspec/lib.ui-kit-web/ui/label";
|
|
403
|
+
import {
|
|
404
|
+
Select,
|
|
405
|
+
SelectContent,
|
|
406
|
+
SelectItem,
|
|
407
|
+
SelectTrigger,
|
|
408
|
+
SelectValue
|
|
409
|
+
} from "@contractspec/lib.ui-kit-web/ui/select";
|
|
410
|
+
import { Checkbox } from "@contractspec/lib.ui-kit-web/ui/checkbox";
|
|
411
|
+
import { Switch } from "@contractspec/lib.ui-kit-web/ui/switch";
|
|
412
|
+
import { Input } from "@contractspec/lib.design-system";
|
|
413
|
+
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
|
|
414
|
+
"use client";
|
|
415
|
+
var simpleWaitlistSchema = z.object({
|
|
416
|
+
email: z.email("Please enter a valid email address")
|
|
417
|
+
});
|
|
418
|
+
var designPartnerSchema = z.object({
|
|
419
|
+
name: z.string().min(1, "Name is required"),
|
|
420
|
+
email: z.email("Please enter a valid email address"),
|
|
421
|
+
company: z.string().optional(),
|
|
422
|
+
role: z.string().optional(),
|
|
423
|
+
useCase: z.string().optional(),
|
|
424
|
+
currentStack: z.string().optional(),
|
|
425
|
+
whatBuilding: z.string().min(1, "Please tell us what you are building"),
|
|
426
|
+
whatSolving: z.string().min(1, "Please tell us what ContractSpec will solve for you"),
|
|
427
|
+
teamSize: z.string().optional(),
|
|
428
|
+
timeline: z.string().optional(),
|
|
429
|
+
openToSessions: z.boolean().default(false),
|
|
430
|
+
okayWithCaseStudies: z.boolean().default(false)
|
|
431
|
+
});
|
|
432
|
+
function WaitlistSection({
|
|
433
|
+
variant = "default",
|
|
434
|
+
context = "pricing"
|
|
435
|
+
}) {
|
|
436
|
+
const [isDesignPartner, setIsDesignPartner] = useState(false);
|
|
437
|
+
const [submitResult, setSubmitResult] = useState(null);
|
|
438
|
+
const [isPending, setIsPending] = useState(false);
|
|
439
|
+
const simpleForm = useForm({
|
|
440
|
+
resolver: zodResolver(simpleWaitlistSchema),
|
|
441
|
+
defaultValues: {
|
|
442
|
+
email: ""
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
const designPartnerForm = useForm({
|
|
446
|
+
resolver: zodResolver(designPartnerSchema),
|
|
447
|
+
defaultValues: {
|
|
448
|
+
name: "",
|
|
449
|
+
email: "",
|
|
450
|
+
company: "",
|
|
451
|
+
role: "",
|
|
452
|
+
useCase: "",
|
|
453
|
+
currentStack: "",
|
|
454
|
+
whatBuilding: "",
|
|
455
|
+
whatSolving: "",
|
|
456
|
+
teamSize: "",
|
|
457
|
+
timeline: "",
|
|
458
|
+
openToSessions: false,
|
|
459
|
+
okayWithCaseStudies: false
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
const simpleEmail = simpleForm.watch("email");
|
|
463
|
+
const designPartnerEmail = designPartnerForm.watch("email");
|
|
464
|
+
useEffect(() => {
|
|
465
|
+
const currentDesignPartnerEmail = designPartnerForm.getValues("email");
|
|
466
|
+
if (simpleEmail && simpleEmail !== currentDesignPartnerEmail) {
|
|
467
|
+
designPartnerForm.setValue("email", simpleEmail, { shouldDirty: false });
|
|
468
|
+
}
|
|
469
|
+
}, [simpleEmail, designPartnerForm]);
|
|
470
|
+
useEffect(() => {
|
|
471
|
+
const currentSimpleEmail = simpleForm.getValues("email");
|
|
472
|
+
if (designPartnerEmail && designPartnerEmail !== currentSimpleEmail) {
|
|
473
|
+
simpleForm.setValue("email", designPartnerEmail, { shouldDirty: false });
|
|
474
|
+
}
|
|
475
|
+
}, [designPartnerEmail, simpleForm]);
|
|
476
|
+
const handleSimpleSubmit = async (data) => {
|
|
477
|
+
setIsPending(true);
|
|
478
|
+
setSubmitResult(null);
|
|
479
|
+
try {
|
|
480
|
+
const formData = new FormData;
|
|
481
|
+
formData.set("email", data.email);
|
|
482
|
+
const result = await joinWaitlist(formData);
|
|
483
|
+
if (result.success) {
|
|
484
|
+
setSubmitResult({
|
|
485
|
+
success: true,
|
|
486
|
+
text: "Thanks for joining the waitlist! Check your inbox for a confirmation."
|
|
487
|
+
});
|
|
488
|
+
simpleForm.reset();
|
|
489
|
+
} else {
|
|
490
|
+
setSubmitResult({
|
|
491
|
+
success: false,
|
|
492
|
+
text: result.text || "Failed to join waitlist. Please try again."
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
} catch (_error) {
|
|
496
|
+
setSubmitResult({
|
|
497
|
+
success: false,
|
|
498
|
+
text: "Failed to join waitlist. Please try again."
|
|
499
|
+
});
|
|
500
|
+
} finally {
|
|
501
|
+
setIsPending(false);
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
const handleDesignPartnerSubmit = async (data) => {
|
|
505
|
+
setIsPending(true);
|
|
506
|
+
setSubmitResult(null);
|
|
507
|
+
try {
|
|
508
|
+
const formData = new FormData;
|
|
509
|
+
formData.set("email", data.email);
|
|
510
|
+
formData.set("name", data.name);
|
|
511
|
+
if (data.company)
|
|
512
|
+
formData.set("company", data.company);
|
|
513
|
+
if (data.role)
|
|
514
|
+
formData.set("role", data.role);
|
|
515
|
+
if (data.useCase)
|
|
516
|
+
formData.set("useCase", data.useCase);
|
|
517
|
+
if (data.currentStack)
|
|
518
|
+
formData.set("currentStack", data.currentStack);
|
|
519
|
+
formData.set("whatBuilding", data.whatBuilding);
|
|
520
|
+
formData.set("whatSolving", data.whatSolving);
|
|
521
|
+
if (data.teamSize)
|
|
522
|
+
formData.set("teamSize", data.teamSize);
|
|
523
|
+
if (data.timeline)
|
|
524
|
+
formData.set("timeline", data.timeline);
|
|
525
|
+
if (data.openToSessions)
|
|
526
|
+
formData.set("openToSessions", "on");
|
|
527
|
+
if (data.okayWithCaseStudies)
|
|
528
|
+
formData.set("okayWithCaseStudies", "on");
|
|
529
|
+
const result = await submitWaitlistApplication(formData);
|
|
530
|
+
if (result.success) {
|
|
531
|
+
setSubmitResult({
|
|
532
|
+
success: true,
|
|
533
|
+
text: "You're on the list. Thanks for applying. We're slowly onboarding design partners in waves. If your use case is a good fit, we'll reach out personally."
|
|
534
|
+
});
|
|
535
|
+
designPartnerForm.reset();
|
|
536
|
+
} else {
|
|
537
|
+
setSubmitResult({
|
|
538
|
+
success: false,
|
|
539
|
+
text: result.text || "Failed to submit application. Please try again."
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
} catch (_error) {
|
|
543
|
+
setSubmitResult({
|
|
544
|
+
success: false,
|
|
545
|
+
text: "Failed to submit application. Please try again."
|
|
546
|
+
});
|
|
547
|
+
} finally {
|
|
548
|
+
setIsPending(false);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
const onSubmit = isDesignPartner ? designPartnerForm.handleSubmit(handleDesignPartnerSubmit) : simpleForm.handleSubmit(handleSimpleSubmit);
|
|
552
|
+
const isCompact = variant === "compact";
|
|
553
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
554
|
+
id: "waitlist",
|
|
555
|
+
className: isCompact ? "space-y-4" : "card-subtle space-y-6 p-8",
|
|
556
|
+
children: [
|
|
557
|
+
!isCompact && /* @__PURE__ */ jsxDEV("div", {
|
|
558
|
+
className: "space-y-4",
|
|
559
|
+
children: [
|
|
560
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
561
|
+
className: "inline-flex items-center gap-2 rounded-full border border-violet-500/20 bg-violet-500/10 px-3 py-1",
|
|
562
|
+
children: /* @__PURE__ */ jsxDEV("span", {
|
|
563
|
+
className: "text-sm font-medium text-violet-300",
|
|
564
|
+
children: isDesignPartner ? "Design Partner Waitlist" : "Join the Waitlist"
|
|
565
|
+
}, undefined, false, undefined, this)
|
|
566
|
+
}, undefined, false, undefined, this),
|
|
567
|
+
/* @__PURE__ */ jsxDEV("h2", {
|
|
568
|
+
className: "text-2xl font-bold",
|
|
569
|
+
children: isDesignPartner ? "Apply for early access to ContractSpec" : "Get early access to ContractSpec"
|
|
570
|
+
}, undefined, false, undefined, this),
|
|
571
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
572
|
+
className: "text-muted-foreground text-sm",
|
|
573
|
+
children: isDesignPartner ? "Tell us what you're building. We'll prioritize teams where ContractSpec can have a big impact, and where we can learn the most." : "Join the waitlist to be notified when ContractSpec becomes available."
|
|
574
|
+
}, undefined, false, undefined, this)
|
|
575
|
+
]
|
|
576
|
+
}, undefined, true, undefined, this),
|
|
577
|
+
!isCompact && /* @__PURE__ */ jsxDEV("div", {
|
|
578
|
+
className: "border-border bg-muted/20 flex items-center justify-between gap-4 rounded-lg border p-4",
|
|
579
|
+
children: [
|
|
580
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
581
|
+
className: "space-y-1",
|
|
582
|
+
children: [
|
|
583
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
584
|
+
htmlFor: "design-partner-toggle",
|
|
585
|
+
className: "text-sm font-medium",
|
|
586
|
+
children: "Apply as a design partner"
|
|
587
|
+
}, undefined, false, undefined, this),
|
|
588
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
589
|
+
className: "text-muted-foreground text-xs",
|
|
590
|
+
children: isDesignPartner ? "Get hands-on support, influence the roadmap, and founding discount" : "Get priority access, 1:1 onboarding, and help shape ContractSpec"
|
|
591
|
+
}, undefined, false, undefined, this)
|
|
592
|
+
]
|
|
593
|
+
}, undefined, true, undefined, this),
|
|
594
|
+
/* @__PURE__ */ jsxDEV(Switch, {
|
|
595
|
+
id: "design-partner-toggle",
|
|
596
|
+
checked: isDesignPartner,
|
|
597
|
+
onCheckedChange: setIsDesignPartner,
|
|
598
|
+
disabled: isPending || submitResult?.success
|
|
599
|
+
}, undefined, false, undefined, this)
|
|
600
|
+
]
|
|
601
|
+
}, undefined, true, undefined, this),
|
|
602
|
+
!isCompact && isDesignPartner && /* @__PURE__ */ jsxDEV("div", {
|
|
603
|
+
className: "space-y-2",
|
|
604
|
+
children: [
|
|
605
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
606
|
+
className: "text-sm font-medium",
|
|
607
|
+
children: "Benefits:"
|
|
608
|
+
}, undefined, false, undefined, this),
|
|
609
|
+
/* @__PURE__ */ jsxDEV("ul", {
|
|
610
|
+
className: "text-muted-foreground space-y-1 text-sm",
|
|
611
|
+
children: [
|
|
612
|
+
/* @__PURE__ */ jsxDEV("li", {
|
|
613
|
+
children: "• Early access to ContractSpec Studio"
|
|
614
|
+
}, undefined, false, undefined, this),
|
|
615
|
+
/* @__PURE__ */ jsxDEV("li", {
|
|
616
|
+
children: "• 1:1 onboarding and architecture sessions"
|
|
617
|
+
}, undefined, false, undefined, this),
|
|
618
|
+
/* @__PURE__ */ jsxDEV("li", {
|
|
619
|
+
children: "• Priority support via direct channels"
|
|
620
|
+
}, undefined, false, undefined, this),
|
|
621
|
+
/* @__PURE__ */ jsxDEV("li", {
|
|
622
|
+
children: "• Influence over roadmap and features"
|
|
623
|
+
}, undefined, false, undefined, this),
|
|
624
|
+
/* @__PURE__ */ jsxDEV("li", {
|
|
625
|
+
children: "• Founding discount when paid plans launch"
|
|
626
|
+
}, undefined, false, undefined, this)
|
|
627
|
+
]
|
|
628
|
+
}, undefined, true, undefined, this)
|
|
629
|
+
]
|
|
630
|
+
}, undefined, true, undefined, this),
|
|
631
|
+
/* @__PURE__ */ jsxDEV("form", {
|
|
632
|
+
onSubmit,
|
|
633
|
+
className: "space-y-4",
|
|
634
|
+
children: [
|
|
635
|
+
isDesignPartner ? /* @__PURE__ */ jsxDEV(Fragment, {
|
|
636
|
+
children: [
|
|
637
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
638
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
639
|
+
children: [
|
|
640
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
641
|
+
className: "space-y-2",
|
|
642
|
+
children: [
|
|
643
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
644
|
+
htmlFor: "waitlist-name",
|
|
645
|
+
className: "text-sm font-medium",
|
|
646
|
+
children: [
|
|
647
|
+
"Name ",
|
|
648
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
649
|
+
className: "text-red-400",
|
|
650
|
+
children: "*"
|
|
651
|
+
}, undefined, false, undefined, this)
|
|
652
|
+
]
|
|
653
|
+
}, undefined, true, undefined, this),
|
|
654
|
+
/* @__PURE__ */ jsxDEV(Input, {
|
|
655
|
+
id: "waitlist-name",
|
|
656
|
+
...designPartnerForm.register("name"),
|
|
657
|
+
type: "text",
|
|
658
|
+
placeholder: "Your name",
|
|
659
|
+
disabled: isPending || submitResult?.success
|
|
660
|
+
}, undefined, false, undefined, this),
|
|
661
|
+
designPartnerForm.formState.errors.name && /* @__PURE__ */ jsxDEV("p", {
|
|
662
|
+
className: "text-xs text-red-400",
|
|
663
|
+
children: designPartnerForm.formState.errors.name.message
|
|
664
|
+
}, undefined, false, undefined, this)
|
|
665
|
+
]
|
|
666
|
+
}, undefined, true, undefined, this),
|
|
667
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
668
|
+
className: "space-y-2",
|
|
669
|
+
children: [
|
|
670
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
671
|
+
htmlFor: "waitlist-email",
|
|
672
|
+
className: "text-sm font-medium",
|
|
673
|
+
children: [
|
|
674
|
+
"Email ",
|
|
675
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
676
|
+
className: "text-red-400",
|
|
677
|
+
children: "*"
|
|
678
|
+
}, undefined, false, undefined, this)
|
|
679
|
+
]
|
|
680
|
+
}, undefined, true, undefined, this),
|
|
681
|
+
/* @__PURE__ */ jsxDEV(Input, {
|
|
682
|
+
id: "waitlist-email",
|
|
683
|
+
...designPartnerForm.register("email"),
|
|
684
|
+
type: "email",
|
|
685
|
+
placeholder: "your@email.com",
|
|
686
|
+
disabled: isPending || submitResult?.success
|
|
687
|
+
}, undefined, false, undefined, this),
|
|
688
|
+
designPartnerForm.formState.errors.email && /* @__PURE__ */ jsxDEV("p", {
|
|
689
|
+
className: "text-xs text-red-400",
|
|
690
|
+
children: designPartnerForm.formState.errors.email.message
|
|
691
|
+
}, undefined, false, undefined, this)
|
|
692
|
+
]
|
|
693
|
+
}, undefined, true, undefined, this)
|
|
694
|
+
]
|
|
695
|
+
}, undefined, true, undefined, this),
|
|
696
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
697
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
698
|
+
children: [
|
|
699
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
700
|
+
className: "space-y-2",
|
|
701
|
+
children: [
|
|
702
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
703
|
+
htmlFor: "waitlist-company",
|
|
704
|
+
className: "text-sm font-medium",
|
|
705
|
+
children: "Company / Project Name"
|
|
706
|
+
}, undefined, false, undefined, this),
|
|
707
|
+
/* @__PURE__ */ jsxDEV(Input, {
|
|
708
|
+
id: "waitlist-company",
|
|
709
|
+
...designPartnerForm.register("company"),
|
|
710
|
+
type: "text",
|
|
711
|
+
placeholder: "Your company or project",
|
|
712
|
+
disabled: isPending || submitResult?.success
|
|
713
|
+
}, undefined, false, undefined, this)
|
|
714
|
+
]
|
|
715
|
+
}, undefined, true, undefined, this),
|
|
716
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
717
|
+
className: "space-y-2",
|
|
718
|
+
children: [
|
|
719
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
720
|
+
htmlFor: "waitlist-role",
|
|
721
|
+
className: "text-sm font-medium",
|
|
722
|
+
children: "Role"
|
|
723
|
+
}, undefined, false, undefined, this),
|
|
724
|
+
/* @__PURE__ */ jsxDEV(Select, {
|
|
725
|
+
value: designPartnerForm.watch("role") || "",
|
|
726
|
+
onValueChange: (value) => designPartnerForm.setValue("role", value),
|
|
727
|
+
disabled: isPending || submitResult?.success,
|
|
728
|
+
children: [
|
|
729
|
+
/* @__PURE__ */ jsxDEV(SelectTrigger, {
|
|
730
|
+
id: "waitlist-role",
|
|
731
|
+
className: "w-full",
|
|
732
|
+
children: /* @__PURE__ */ jsxDEV(SelectValue, {
|
|
733
|
+
placeholder: "Select your role"
|
|
734
|
+
}, undefined, false, undefined, this)
|
|
735
|
+
}, undefined, false, undefined, this),
|
|
736
|
+
/* @__PURE__ */ jsxDEV(SelectContent, {
|
|
737
|
+
children: [
|
|
738
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
739
|
+
value: "founder",
|
|
740
|
+
children: "Founder"
|
|
741
|
+
}, undefined, false, undefined, this),
|
|
742
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
743
|
+
value: "cto",
|
|
744
|
+
children: "CTO"
|
|
745
|
+
}, undefined, false, undefined, this),
|
|
746
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
747
|
+
value: "lead-engineer",
|
|
748
|
+
children: "Lead Engineer"
|
|
749
|
+
}, undefined, false, undefined, this),
|
|
750
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
751
|
+
value: "engineer",
|
|
752
|
+
children: "Engineer"
|
|
753
|
+
}, undefined, false, undefined, this),
|
|
754
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
755
|
+
value: "product-manager",
|
|
756
|
+
children: "Product Manager"
|
|
757
|
+
}, undefined, false, undefined, this),
|
|
758
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
759
|
+
value: "other",
|
|
760
|
+
children: "Other"
|
|
761
|
+
}, undefined, false, undefined, this)
|
|
762
|
+
]
|
|
763
|
+
}, undefined, true, undefined, this)
|
|
764
|
+
]
|
|
765
|
+
}, undefined, true, undefined, this)
|
|
766
|
+
]
|
|
767
|
+
}, undefined, true, undefined, this)
|
|
768
|
+
]
|
|
769
|
+
}, undefined, true, undefined, this),
|
|
770
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
771
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
772
|
+
children: [
|
|
773
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
774
|
+
className: "space-y-2",
|
|
775
|
+
children: [
|
|
776
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
777
|
+
htmlFor: "waitlist-use-case",
|
|
778
|
+
className: "text-sm font-medium",
|
|
779
|
+
children: "Primary use case"
|
|
780
|
+
}, undefined, false, undefined, this),
|
|
781
|
+
/* @__PURE__ */ jsxDEV(Select, {
|
|
782
|
+
value: designPartnerForm.watch("useCase") || "",
|
|
783
|
+
onValueChange: (value) => designPartnerForm.setValue("useCase", value),
|
|
784
|
+
disabled: isPending || submitResult?.success,
|
|
785
|
+
children: [
|
|
786
|
+
/* @__PURE__ */ jsxDEV(SelectTrigger, {
|
|
787
|
+
id: "waitlist-use-case",
|
|
788
|
+
className: "w-full",
|
|
789
|
+
children: /* @__PURE__ */ jsxDEV(SelectValue, {
|
|
790
|
+
placeholder: "Select a use case"
|
|
791
|
+
}, undefined, false, undefined, this)
|
|
792
|
+
}, undefined, false, undefined, this),
|
|
793
|
+
/* @__PURE__ */ jsxDEV(SelectContent, {
|
|
794
|
+
children: [
|
|
795
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
796
|
+
value: "api-platform",
|
|
797
|
+
children: "API platform"
|
|
798
|
+
}, undefined, false, undefined, this),
|
|
799
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
800
|
+
value: "ai-ops",
|
|
801
|
+
children: "AI operations"
|
|
802
|
+
}, undefined, false, undefined, this),
|
|
803
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
804
|
+
value: "integration-hub",
|
|
805
|
+
children: "Integration hub"
|
|
806
|
+
}, undefined, false, undefined, this),
|
|
807
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
808
|
+
value: "internal-tools",
|
|
809
|
+
children: "Internal tools"
|
|
810
|
+
}, undefined, false, undefined, this),
|
|
811
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
812
|
+
value: "data-pipelines",
|
|
813
|
+
children: "Data pipelines"
|
|
814
|
+
}, undefined, false, undefined, this),
|
|
815
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
816
|
+
value: "other",
|
|
817
|
+
children: "Other"
|
|
818
|
+
}, undefined, false, undefined, this)
|
|
819
|
+
]
|
|
820
|
+
}, undefined, true, undefined, this)
|
|
821
|
+
]
|
|
822
|
+
}, undefined, true, undefined, this)
|
|
823
|
+
]
|
|
824
|
+
}, undefined, true, undefined, this),
|
|
825
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
826
|
+
className: "space-y-2",
|
|
827
|
+
children: [
|
|
828
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
829
|
+
htmlFor: "waitlist-current-stack",
|
|
830
|
+
className: "text-sm font-medium",
|
|
831
|
+
children: "Current stack"
|
|
832
|
+
}, undefined, false, undefined, this),
|
|
833
|
+
/* @__PURE__ */ jsxDEV(Input, {
|
|
834
|
+
id: "waitlist-current-stack",
|
|
835
|
+
...designPartnerForm.register("currentStack"),
|
|
836
|
+
type: "text",
|
|
837
|
+
placeholder: "e.g. Next.js, Postgres, OpenAPI",
|
|
838
|
+
disabled: isPending || submitResult?.success
|
|
839
|
+
}, undefined, false, undefined, this)
|
|
840
|
+
]
|
|
841
|
+
}, undefined, true, undefined, this)
|
|
842
|
+
]
|
|
843
|
+
}, undefined, true, undefined, this),
|
|
844
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
845
|
+
className: "space-y-2",
|
|
846
|
+
children: [
|
|
847
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
848
|
+
htmlFor: "waitlist-what-building",
|
|
849
|
+
className: "text-sm font-medium",
|
|
850
|
+
children: [
|
|
851
|
+
"What are you building with AI today?",
|
|
852
|
+
" ",
|
|
853
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
854
|
+
className: "text-red-400",
|
|
855
|
+
children: "*"
|
|
856
|
+
}, undefined, false, undefined, this)
|
|
857
|
+
]
|
|
858
|
+
}, undefined, true, undefined, this),
|
|
859
|
+
/* @__PURE__ */ jsxDEV(Textarea, {
|
|
860
|
+
id: "waitlist-what-building",
|
|
861
|
+
...designPartnerForm.register("whatBuilding"),
|
|
862
|
+
placeholder: "Tell us about your project...",
|
|
863
|
+
disabled: isPending || submitResult?.success,
|
|
864
|
+
rows: 4
|
|
865
|
+
}, undefined, false, undefined, this),
|
|
866
|
+
designPartnerForm.formState.errors.whatBuilding && /* @__PURE__ */ jsxDEV("p", {
|
|
867
|
+
className: "text-xs text-red-400",
|
|
868
|
+
children: designPartnerForm.formState.errors.whatBuilding.message
|
|
869
|
+
}, undefined, false, undefined, this)
|
|
870
|
+
]
|
|
871
|
+
}, undefined, true, undefined, this),
|
|
872
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
873
|
+
className: "space-y-2",
|
|
874
|
+
children: [
|
|
875
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
876
|
+
htmlFor: "waitlist-what-solving",
|
|
877
|
+
className: "text-sm font-medium",
|
|
878
|
+
children: [
|
|
879
|
+
"What do you hope ContractSpec will solve for you?",
|
|
880
|
+
" ",
|
|
881
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
882
|
+
className: "text-red-400",
|
|
883
|
+
children: "*"
|
|
884
|
+
}, undefined, false, undefined, this)
|
|
885
|
+
]
|
|
886
|
+
}, undefined, true, undefined, this),
|
|
887
|
+
/* @__PURE__ */ jsxDEV(Textarea, {
|
|
888
|
+
id: "waitlist-what-solving",
|
|
889
|
+
...designPartnerForm.register("whatSolving"),
|
|
890
|
+
placeholder: "What problems are you trying to solve?",
|
|
891
|
+
disabled: isPending || submitResult?.success,
|
|
892
|
+
rows: 4
|
|
893
|
+
}, undefined, false, undefined, this),
|
|
894
|
+
designPartnerForm.formState.errors.whatSolving && /* @__PURE__ */ jsxDEV("p", {
|
|
895
|
+
className: "text-xs text-red-400",
|
|
896
|
+
children: designPartnerForm.formState.errors.whatSolving.message
|
|
897
|
+
}, undefined, false, undefined, this)
|
|
898
|
+
]
|
|
899
|
+
}, undefined, true, undefined, this),
|
|
900
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
901
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
902
|
+
children: [
|
|
903
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
904
|
+
className: "space-y-2",
|
|
905
|
+
children: [
|
|
906
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
907
|
+
htmlFor: "waitlist-team-size",
|
|
908
|
+
className: "text-sm font-medium",
|
|
909
|
+
children: "Team Size"
|
|
910
|
+
}, undefined, false, undefined, this),
|
|
911
|
+
/* @__PURE__ */ jsxDEV(Select, {
|
|
912
|
+
value: designPartnerForm.watch("teamSize") || "",
|
|
913
|
+
onValueChange: (value) => designPartnerForm.setValue("teamSize", value),
|
|
914
|
+
disabled: isPending || submitResult?.success,
|
|
915
|
+
children: [
|
|
916
|
+
/* @__PURE__ */ jsxDEV(SelectTrigger, {
|
|
917
|
+
id: "waitlist-team-size",
|
|
918
|
+
className: "w-full",
|
|
919
|
+
children: /* @__PURE__ */ jsxDEV(SelectValue, {
|
|
920
|
+
placeholder: "Select team size"
|
|
921
|
+
}, undefined, false, undefined, this)
|
|
922
|
+
}, undefined, false, undefined, this),
|
|
923
|
+
/* @__PURE__ */ jsxDEV(SelectContent, {
|
|
924
|
+
children: [
|
|
925
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
926
|
+
value: "solo",
|
|
927
|
+
children: "Solo"
|
|
928
|
+
}, undefined, false, undefined, this),
|
|
929
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
930
|
+
value: "2-5",
|
|
931
|
+
children: "2-5"
|
|
932
|
+
}, undefined, false, undefined, this),
|
|
933
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
934
|
+
value: "6-20",
|
|
935
|
+
children: "6-20"
|
|
936
|
+
}, undefined, false, undefined, this),
|
|
937
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
938
|
+
value: "20+",
|
|
939
|
+
children: "20+"
|
|
940
|
+
}, undefined, false, undefined, this)
|
|
941
|
+
]
|
|
942
|
+
}, undefined, true, undefined, this)
|
|
943
|
+
]
|
|
944
|
+
}, undefined, true, undefined, this)
|
|
945
|
+
]
|
|
946
|
+
}, undefined, true, undefined, this),
|
|
947
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
948
|
+
className: "space-y-2",
|
|
949
|
+
children: [
|
|
950
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
951
|
+
htmlFor: "waitlist-timeline",
|
|
952
|
+
className: "text-sm font-medium",
|
|
953
|
+
children: "Timeline"
|
|
954
|
+
}, undefined, false, undefined, this),
|
|
955
|
+
/* @__PURE__ */ jsxDEV(Select, {
|
|
956
|
+
value: designPartnerForm.watch("timeline") || "",
|
|
957
|
+
onValueChange: (value) => designPartnerForm.setValue("timeline", value),
|
|
958
|
+
disabled: isPending || submitResult?.success,
|
|
959
|
+
children: [
|
|
960
|
+
/* @__PURE__ */ jsxDEV(SelectTrigger, {
|
|
961
|
+
id: "waitlist-timeline",
|
|
962
|
+
className: "w-full",
|
|
963
|
+
children: /* @__PURE__ */ jsxDEV(SelectValue, {
|
|
964
|
+
placeholder: "Select timeline"
|
|
965
|
+
}, undefined, false, undefined, this)
|
|
966
|
+
}, undefined, false, undefined, this),
|
|
967
|
+
/* @__PURE__ */ jsxDEV(SelectContent, {
|
|
968
|
+
children: [
|
|
969
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
970
|
+
value: "now",
|
|
971
|
+
children: "Now"
|
|
972
|
+
}, undefined, false, undefined, this),
|
|
973
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
974
|
+
value: "1-3-months",
|
|
975
|
+
children: "1-3 months"
|
|
976
|
+
}, undefined, false, undefined, this),
|
|
977
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
978
|
+
value: "3-6-months",
|
|
979
|
+
children: "3-6 months"
|
|
980
|
+
}, undefined, false, undefined, this),
|
|
981
|
+
/* @__PURE__ */ jsxDEV(SelectItem, {
|
|
982
|
+
value: "exploring",
|
|
983
|
+
children: "Exploring"
|
|
984
|
+
}, undefined, false, undefined, this)
|
|
985
|
+
]
|
|
986
|
+
}, undefined, true, undefined, this)
|
|
987
|
+
]
|
|
988
|
+
}, undefined, true, undefined, this)
|
|
989
|
+
]
|
|
990
|
+
}, undefined, true, undefined, this)
|
|
991
|
+
]
|
|
992
|
+
}, undefined, true, undefined, this),
|
|
993
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
994
|
+
className: "space-y-3",
|
|
995
|
+
children: [
|
|
996
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
997
|
+
className: "flex items-start gap-3",
|
|
998
|
+
children: [
|
|
999
|
+
/* @__PURE__ */ jsxDEV(Checkbox, {
|
|
1000
|
+
id: "waitlist-open-to-sessions",
|
|
1001
|
+
checked: designPartnerForm.watch("openToSessions"),
|
|
1002
|
+
onCheckedChange: (checked) => designPartnerForm.setValue("openToSessions", checked === true),
|
|
1003
|
+
disabled: isPending || submitResult?.success
|
|
1004
|
+
}, undefined, false, undefined, this),
|
|
1005
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
1006
|
+
htmlFor: "waitlist-open-to-sessions",
|
|
1007
|
+
className: "cursor-pointer text-sm leading-relaxed",
|
|
1008
|
+
children: "I'm open to 1:1 product/design sessions"
|
|
1009
|
+
}, undefined, false, undefined, this)
|
|
1010
|
+
]
|
|
1011
|
+
}, undefined, true, undefined, this),
|
|
1012
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
1013
|
+
className: "flex items-start gap-3",
|
|
1014
|
+
children: [
|
|
1015
|
+
/* @__PURE__ */ jsxDEV(Checkbox, {
|
|
1016
|
+
id: "waitlist-case-studies",
|
|
1017
|
+
checked: designPartnerForm.watch("okayWithCaseStudies"),
|
|
1018
|
+
onCheckedChange: (checked) => designPartnerForm.setValue("okayWithCaseStudies", checked === true),
|
|
1019
|
+
disabled: isPending || submitResult?.success
|
|
1020
|
+
}, undefined, false, undefined, this),
|
|
1021
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
1022
|
+
htmlFor: "waitlist-case-studies",
|
|
1023
|
+
className: "cursor-pointer text-sm leading-relaxed",
|
|
1024
|
+
children: "I'm okay with anonymized case studies about our usage"
|
|
1025
|
+
}, undefined, false, undefined, this)
|
|
1026
|
+
]
|
|
1027
|
+
}, undefined, true, undefined, this)
|
|
1028
|
+
]
|
|
1029
|
+
}, undefined, true, undefined, this)
|
|
1030
|
+
]
|
|
1031
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV("div", {
|
|
1032
|
+
className: "space-y-2",
|
|
1033
|
+
children: [
|
|
1034
|
+
/* @__PURE__ */ jsxDEV(Label, {
|
|
1035
|
+
htmlFor: "waitlist-email",
|
|
1036
|
+
className: "text-sm font-medium",
|
|
1037
|
+
children: [
|
|
1038
|
+
"Email ",
|
|
1039
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
1040
|
+
className: "text-red-400",
|
|
1041
|
+
children: "*"
|
|
1042
|
+
}, undefined, false, undefined, this)
|
|
1043
|
+
]
|
|
1044
|
+
}, undefined, true, undefined, this),
|
|
1045
|
+
/* @__PURE__ */ jsxDEV(Input, {
|
|
1046
|
+
id: "waitlist-email",
|
|
1047
|
+
...simpleForm.register("email"),
|
|
1048
|
+
type: "email",
|
|
1049
|
+
placeholder: "your@email.com",
|
|
1050
|
+
disabled: isPending || submitResult?.success
|
|
1051
|
+
}, undefined, false, undefined, this),
|
|
1052
|
+
simpleForm.formState.errors.email && /* @__PURE__ */ jsxDEV("p", {
|
|
1053
|
+
className: "text-xs text-red-400",
|
|
1054
|
+
children: simpleForm.formState.errors.email.message
|
|
1055
|
+
}, undefined, false, undefined, this)
|
|
1056
|
+
]
|
|
1057
|
+
}, undefined, true, undefined, this),
|
|
1058
|
+
submitResult && !isPending && /* @__PURE__ */ jsxDEV("div", {
|
|
1059
|
+
className: `flex items-start gap-2 rounded-lg p-4 text-sm ${submitResult.success ? "border border-green-500/20 bg-green-500/10 text-green-400" : "border border-red-500/20 bg-red-500/10 text-red-400"}`,
|
|
1060
|
+
children: [
|
|
1061
|
+
submitResult.success ? /* @__PURE__ */ jsxDEV(CheckCircle, {
|
|
1062
|
+
size: 20,
|
|
1063
|
+
className: "mt-0.5 shrink-0"
|
|
1064
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV(AlertCircle, {
|
|
1065
|
+
size: 20,
|
|
1066
|
+
className: "mt-0.5 shrink-0"
|
|
1067
|
+
}, undefined, false, undefined, this),
|
|
1068
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
1069
|
+
className: "flex-1",
|
|
1070
|
+
children: submitResult.success ? /* @__PURE__ */ jsxDEV(Fragment, {
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
1073
|
+
className: "mb-1 font-semibold",
|
|
1074
|
+
children: "You're on the list."
|
|
1075
|
+
}, undefined, false, undefined, this),
|
|
1076
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
1077
|
+
className: "text-sm",
|
|
1078
|
+
children: submitResult.text
|
|
1079
|
+
}, undefined, false, undefined, this)
|
|
1080
|
+
]
|
|
1081
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV("p", {
|
|
1082
|
+
children: submitResult.text
|
|
1083
|
+
}, undefined, false, undefined, this)
|
|
1084
|
+
}, undefined, false, undefined, this)
|
|
1085
|
+
]
|
|
1086
|
+
}, undefined, true, undefined, this),
|
|
1087
|
+
/* @__PURE__ */ jsxDEV(Button, {
|
|
1088
|
+
type: "submit",
|
|
1089
|
+
disabled: isPending || submitResult?.success,
|
|
1090
|
+
className: "w-full",
|
|
1091
|
+
children: isPending ? "Submitting..." : isDesignPartner ? "Apply to the waitlist" : "Join waitlist"
|
|
1092
|
+
}, undefined, false, undefined, this),
|
|
1093
|
+
/* @__PURE__ */ jsxDEV("p", {
|
|
1094
|
+
className: "text-muted-foreground text-center text-xs",
|
|
1095
|
+
children: "No spam. We'll only email you about ContractSpec and your application."
|
|
1096
|
+
}, undefined, false, undefined, this)
|
|
1097
|
+
]
|
|
1098
|
+
}, undefined, true, undefined, this)
|
|
1099
|
+
]
|
|
1100
|
+
}, undefined, true, undefined, this);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// src/libs/pricing-examples.ts
|
|
1104
|
+
var PRICING_EXAMPLES = {
|
|
1105
|
+
free: {
|
|
1106
|
+
regenerationsPerMonth: 200,
|
|
1107
|
+
aiActionsPerMonth: 100,
|
|
1108
|
+
projects: 1
|
|
1109
|
+
},
|
|
1110
|
+
builder: {
|
|
1111
|
+
regenerationsPerMonthHint: "1,000–2,000+",
|
|
1112
|
+
aiActionsPerMonthHint: "1,000+"
|
|
1113
|
+
},
|
|
1114
|
+
team: {
|
|
1115
|
+
description: "Higher limits + cheaper per-regen at scale"
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
// src/components/marketing/pricing-thinking-modal.tsx
|
|
1120
|
+
import { CheckCircle as CheckCircle2 } from "lucide-react";
|
|
1121
|
+
import {
|
|
1122
|
+
Dialog,
|
|
1123
|
+
DialogContent,
|
|
1124
|
+
DialogDescription,
|
|
1125
|
+
DialogHeader,
|
|
1126
|
+
DialogTitle
|
|
1127
|
+
} from "@contractspec/lib.ui-kit-web/ui/dialog";
|
|
1128
|
+
import { Button as Button2 } from "@contractspec/lib.design-system";
|
|
1129
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
1130
|
+
"use client";
|
|
1131
|
+
var pricingTiers = [
|
|
1132
|
+
{
|
|
1133
|
+
tag: "Planned",
|
|
1134
|
+
title: "Free",
|
|
1135
|
+
priceLine: "For hobbyists and pre-PMF teams",
|
|
1136
|
+
bullets: [
|
|
1137
|
+
"1 active project",
|
|
1138
|
+
"Small spec size",
|
|
1139
|
+
`Example: ~${PRICING_EXAMPLES.free.regenerationsPerMonth} free regenerations per month`,
|
|
1140
|
+
`Example: ~${PRICING_EXAMPLES.free.aiActionsPerMonth} free AI agent actions per month`,
|
|
1141
|
+
"Unlimited collaborators"
|
|
1142
|
+
],
|
|
1143
|
+
note: "Good enough to build and launch a real product before paying."
|
|
1144
|
+
},
|
|
1145
|
+
{
|
|
1146
|
+
tag: "Planned",
|
|
1147
|
+
title: "Builder",
|
|
1148
|
+
priceLine: "Usage-based, for solo builders and small teams",
|
|
1149
|
+
bullets: [
|
|
1150
|
+
"More projects",
|
|
1151
|
+
`More monthly regenerations included (e.g. ${PRICING_EXAMPLES.builder.regenerationsPerMonthHint})`,
|
|
1152
|
+
`More AI agent actions included (e.g. ${PRICING_EXAMPLES.builder.aiActionsPerMonthHint})`,
|
|
1153
|
+
"Pay-as-you-go for extra regenerations and AI",
|
|
1154
|
+
"Basic environments (dev / prod)"
|
|
1155
|
+
],
|
|
1156
|
+
note: "Pay for how fast and how often you evolve your system, not for seats."
|
|
1157
|
+
},
|
|
1158
|
+
{
|
|
1159
|
+
tag: "Planned",
|
|
1160
|
+
title: "Team & Platform",
|
|
1161
|
+
priceLine: "For teams standardizing on ContractSpec",
|
|
1162
|
+
bullets: [
|
|
1163
|
+
"Multiple projects and environments",
|
|
1164
|
+
"Higher regeneration and AI action limits",
|
|
1165
|
+
"Cheaper overages as you scale",
|
|
1166
|
+
"Advanced RBAC and governance",
|
|
1167
|
+
"SSO, audit trails, and longer retention"
|
|
1168
|
+
],
|
|
1169
|
+
note: "For platform teams using ContractSpec as infra for multiple apps."
|
|
1170
|
+
}
|
|
1171
|
+
];
|
|
1172
|
+
var usageMetrics = [
|
|
1173
|
+
{
|
|
1174
|
+
name: "Regenerations",
|
|
1175
|
+
freeTier: `Free tier: e.g. ~${PRICING_EXAMPLES.free.regenerationsPerMonth} regenerations / month`,
|
|
1176
|
+
beyond: "Beyond: pay per additional regeneration, with volume discounts."
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
name: "AI agent actions",
|
|
1180
|
+
freeTier: `Free tier: e.g. ~${PRICING_EXAMPLES.free.aiActionsPerMonth} AI agent actions / month`,
|
|
1181
|
+
beyond: "Beyond: pay-as-you-go for extra AI usage."
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
name: "Projects",
|
|
1185
|
+
freeTier: `Free tier: ${PRICING_EXAMPLES.free.projects} project`,
|
|
1186
|
+
beyond: "Builder / Team: more projects included; extra projects available as you scale."
|
|
1187
|
+
}
|
|
1188
|
+
];
|
|
1189
|
+
function PricingThinkingModal({
|
|
1190
|
+
open,
|
|
1191
|
+
onOpenChange,
|
|
1192
|
+
onApplyClick
|
|
1193
|
+
}) {
|
|
1194
|
+
return /* @__PURE__ */ jsxDEV2(Dialog, {
|
|
1195
|
+
open,
|
|
1196
|
+
onOpenChange,
|
|
1197
|
+
children: /* @__PURE__ */ jsxDEV2(DialogContent, {
|
|
1198
|
+
className: "max-h-[90vh] w-full overflow-y-auto md:max-w-5xl",
|
|
1199
|
+
children: [
|
|
1200
|
+
/* @__PURE__ */ jsxDEV2(DialogHeader, {
|
|
1201
|
+
children: [
|
|
1202
|
+
/* @__PURE__ */ jsxDEV2(DialogTitle, {
|
|
1203
|
+
children: "Tentative pricing (work in progress)"
|
|
1204
|
+
}, undefined, false, undefined, this),
|
|
1205
|
+
/* @__PURE__ */ jsxDEV2(DialogDescription, {
|
|
1206
|
+
children: "We're still in design-partner mode. This is a draft of how we expect pricing to look once we open public access."
|
|
1207
|
+
}, undefined, false, undefined, this)
|
|
1208
|
+
]
|
|
1209
|
+
}, undefined, true, undefined, this),
|
|
1210
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1211
|
+
className: "space-y-8",
|
|
1212
|
+
children: [
|
|
1213
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1214
|
+
className: "space-y-4",
|
|
1215
|
+
children: [
|
|
1216
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1217
|
+
className: "flex items-center gap-2",
|
|
1218
|
+
children: [
|
|
1219
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
1220
|
+
className: "text-muted-foreground text-xs font-medium",
|
|
1221
|
+
children: "Draft"
|
|
1222
|
+
}, undefined, false, undefined, this),
|
|
1223
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
1224
|
+
className: "text-muted-foreground text-xs",
|
|
1225
|
+
children: "•"
|
|
1226
|
+
}, undefined, false, undefined, this),
|
|
1227
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
1228
|
+
className: "text-muted-foreground text-xs",
|
|
1229
|
+
children: "Subject to change"
|
|
1230
|
+
}, undefined, false, undefined, this)
|
|
1231
|
+
]
|
|
1232
|
+
}, undefined, true, undefined, this),
|
|
1233
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1234
|
+
className: "grid gap-4 md:grid-cols-3",
|
|
1235
|
+
children: pricingTiers.map((tier) => /* @__PURE__ */ jsxDEV2("div", {
|
|
1236
|
+
className: "card-subtle relative space-y-4 p-6",
|
|
1237
|
+
children: [
|
|
1238
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1239
|
+
className: "bg-muted border-border absolute -top-2 left-1/2 -translate-x-1/2 rounded-full border px-2 py-0.5 text-xs font-medium",
|
|
1240
|
+
children: tier.tag
|
|
1241
|
+
}, undefined, false, undefined, this),
|
|
1242
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1243
|
+
className: "space-y-2 pt-2",
|
|
1244
|
+
children: [
|
|
1245
|
+
/* @__PURE__ */ jsxDEV2("h3", {
|
|
1246
|
+
className: "text-xl font-bold",
|
|
1247
|
+
children: tier.title
|
|
1248
|
+
}, undefined, false, undefined, this),
|
|
1249
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1250
|
+
className: "text-muted-foreground text-sm",
|
|
1251
|
+
children: tier.priceLine
|
|
1252
|
+
}, undefined, false, undefined, this)
|
|
1253
|
+
]
|
|
1254
|
+
}, undefined, true, undefined, this),
|
|
1255
|
+
/* @__PURE__ */ jsxDEV2("ul", {
|
|
1256
|
+
className: "space-y-2",
|
|
1257
|
+
children: tier.bullets.map((bullet, i) => /* @__PURE__ */ jsxDEV2("li", {
|
|
1258
|
+
className: "text-muted-foreground flex gap-2 text-sm",
|
|
1259
|
+
children: [
|
|
1260
|
+
/* @__PURE__ */ jsxDEV2(CheckCircle2, {
|
|
1261
|
+
size: 14,
|
|
1262
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1263
|
+
}, undefined, false, undefined, this),
|
|
1264
|
+
bullet
|
|
1265
|
+
]
|
|
1266
|
+
}, i, true, undefined, this))
|
|
1267
|
+
}, undefined, false, undefined, this),
|
|
1268
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1269
|
+
className: "text-muted-foreground text-xs italic",
|
|
1270
|
+
children: tier.note
|
|
1271
|
+
}, undefined, false, undefined, this)
|
|
1272
|
+
]
|
|
1273
|
+
}, tier.title, true, undefined, this))
|
|
1274
|
+
}, undefined, false, undefined, this)
|
|
1275
|
+
]
|
|
1276
|
+
}, undefined, true, undefined, this),
|
|
1277
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1278
|
+
className: "border-border space-y-4 border-t pt-6",
|
|
1279
|
+
children: [
|
|
1280
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1281
|
+
children: [
|
|
1282
|
+
/* @__PURE__ */ jsxDEV2("h3", {
|
|
1283
|
+
className: "text-lg font-bold",
|
|
1284
|
+
children: "Usage-based, with a generous free tier"
|
|
1285
|
+
}, undefined, false, undefined, this),
|
|
1286
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1287
|
+
className: "text-muted-foreground mt-2 text-sm",
|
|
1288
|
+
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."
|
|
1289
|
+
}, undefined, false, undefined, this),
|
|
1290
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1291
|
+
className: "text-muted-foreground mt-3 text-xs italic",
|
|
1292
|
+
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."
|
|
1293
|
+
}, undefined, false, undefined, this)
|
|
1294
|
+
]
|
|
1295
|
+
}, undefined, true, undefined, this),
|
|
1296
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1297
|
+
className: "grid gap-4 md:grid-cols-3",
|
|
1298
|
+
children: usageMetrics.map((metric) => /* @__PURE__ */ jsxDEV2("div", {
|
|
1299
|
+
className: "card-subtle space-y-2 p-4",
|
|
1300
|
+
children: [
|
|
1301
|
+
/* @__PURE__ */ jsxDEV2("h4", {
|
|
1302
|
+
className: "text-sm font-semibold",
|
|
1303
|
+
children: metric.name
|
|
1304
|
+
}, undefined, false, undefined, this),
|
|
1305
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1306
|
+
className: "text-muted-foreground text-xs",
|
|
1307
|
+
children: metric.freeTier
|
|
1308
|
+
}, undefined, false, undefined, this),
|
|
1309
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1310
|
+
className: "text-muted-foreground text-xs",
|
|
1311
|
+
children: metric.beyond
|
|
1312
|
+
}, undefined, false, undefined, this)
|
|
1313
|
+
]
|
|
1314
|
+
}, metric.name, true, undefined, this))
|
|
1315
|
+
}, undefined, false, undefined, this)
|
|
1316
|
+
]
|
|
1317
|
+
}, undefined, true, undefined, this),
|
|
1318
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1319
|
+
className: "border-border space-y-4 border-t pt-6",
|
|
1320
|
+
children: [
|
|
1321
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1322
|
+
className: "text-muted-foreground text-xs",
|
|
1323
|
+
children: "These numbers are examples only. Final pricing and limits will evolve as we learn from design partners."
|
|
1324
|
+
}, undefined, false, undefined, this),
|
|
1325
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1326
|
+
className: "text-muted-foreground text-xs",
|
|
1327
|
+
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."
|
|
1328
|
+
}, undefined, false, undefined, this),
|
|
1329
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1330
|
+
className: "text-muted-foreground text-xs",
|
|
1331
|
+
children: "Design partners get early access and a founding discount when paid plans launch."
|
|
1332
|
+
}, undefined, false, undefined, this),
|
|
1333
|
+
onApplyClick && /* @__PURE__ */ jsxDEV2(Button2, {
|
|
1334
|
+
onClick: () => {
|
|
1335
|
+
onOpenChange(false);
|
|
1336
|
+
onApplyClick();
|
|
1337
|
+
},
|
|
1338
|
+
className: "w-full",
|
|
1339
|
+
variant: "outline",
|
|
1340
|
+
children: "Apply as a design partner"
|
|
1341
|
+
}, undefined, false, undefined, this)
|
|
1342
|
+
]
|
|
1343
|
+
}, undefined, true, undefined, this)
|
|
1344
|
+
]
|
|
1345
|
+
}, undefined, true, undefined, this)
|
|
1346
|
+
]
|
|
1347
|
+
}, undefined, true, undefined, this)
|
|
1348
|
+
}, undefined, false, undefined, this);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// src/components/marketing/PricingClient.tsx
|
|
1352
|
+
import { useState as useState2 } from "react";
|
|
1353
|
+
import Link from "next/link";
|
|
1354
|
+
import { CheckCircle as CheckCircle3, ChevronDown, ChevronRight } from "lucide-react";
|
|
1355
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
1356
|
+
"use client";
|
|
1357
|
+
var faqs = [
|
|
1358
|
+
{
|
|
1359
|
+
question: "Can I pay for ContractSpec today?",
|
|
1360
|
+
answer: "Not yet. We're pre-PMF and working closely with a small set of design partners. They get full access during early access and will be first to move onto paid plans once we're confident in the value and stability."
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
question: "What will you charge for later?",
|
|
1364
|
+
answer: "Our plan is to charge based on usage: regenerations, AI agent actions, and number of active projects. A generous free tier will stay available so smaller teams and experiments can thrive."
|
|
1365
|
+
},
|
|
1366
|
+
{
|
|
1367
|
+
question: "What do I get as a design partner?",
|
|
1368
|
+
answer: "Direct collaboration on features, priority onboarding, and a founding discount when paid plans launch. You also shape how ContractSpec works for teams like yours."
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
question: "Will you ever charge per seat?",
|
|
1372
|
+
answer: "No. We want everyone in your team to use ContractSpec without friction. Pricing is tied to how much of your system we help you maintain, not how many teammates you invite."
|
|
1373
|
+
}
|
|
1374
|
+
];
|
|
1375
|
+
function PricingClient() {
|
|
1376
|
+
const [openFaq, setOpenFaq] = useState2(null);
|
|
1377
|
+
const [pricingModalOpen, setPricingModalOpen] = useState2(false);
|
|
1378
|
+
const scrollToWaitlist = () => {
|
|
1379
|
+
const waitlistElement = document.getElementById("waitlist");
|
|
1380
|
+
if (waitlistElement) {
|
|
1381
|
+
waitlistElement.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
return /* @__PURE__ */ jsxDEV3("main", {
|
|
1385
|
+
className: "",
|
|
1386
|
+
children: [
|
|
1387
|
+
/* @__PURE__ */ jsxDEV3("section", {
|
|
1388
|
+
className: "section-padding hero-gradient relative",
|
|
1389
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1390
|
+
className: "mx-auto max-w-4xl space-y-6 text-center",
|
|
1391
|
+
children: [
|
|
1392
|
+
/* @__PURE__ */ jsxDEV3("h1", {
|
|
1393
|
+
className: "text-5xl leading-tight font-bold md:text-6xl",
|
|
1394
|
+
children: "Transparent, usage-based pricing – after we earn it."
|
|
1395
|
+
}, undefined, false, undefined, this),
|
|
1396
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1397
|
+
className: "text-muted-foreground mx-auto max-w-2xl text-lg",
|
|
1398
|
+
children: "ContractSpec Core (the OSS compiler) is and always will be free. ContractSpec Studio (the managed platform) is in early access."
|
|
1399
|
+
}, undefined, false, undefined, this),
|
|
1400
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1401
|
+
className: "flex flex-col items-center justify-center gap-4 pt-4 sm:flex-row",
|
|
1402
|
+
children: [
|
|
1403
|
+
/* @__PURE__ */ jsxDEV3(Link, {
|
|
1404
|
+
href: "/install",
|
|
1405
|
+
className: "btn-primary inline-flex items-center gap-2",
|
|
1406
|
+
children: [
|
|
1407
|
+
"Install OSS Core ",
|
|
1408
|
+
/* @__PURE__ */ jsxDEV3(ChevronRight, {
|
|
1409
|
+
size: 16
|
|
1410
|
+
}, undefined, false, undefined, this)
|
|
1411
|
+
]
|
|
1412
|
+
}, undefined, true, undefined, this),
|
|
1413
|
+
/* @__PURE__ */ jsxDEV3("button", {
|
|
1414
|
+
onClick: scrollToWaitlist,
|
|
1415
|
+
className: "btn-ghost inline-flex items-center gap-2",
|
|
1416
|
+
children: "Join Studio waitlist"
|
|
1417
|
+
}, undefined, false, undefined, this)
|
|
1418
|
+
]
|
|
1419
|
+
}, undefined, true, undefined, this)
|
|
1420
|
+
]
|
|
1421
|
+
}, undefined, true, undefined, this)
|
|
1422
|
+
}, undefined, false, undefined, this),
|
|
1423
|
+
/* @__PURE__ */ jsxDEV3("section", {
|
|
1424
|
+
className: "section-padding border-border border-b",
|
|
1425
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1426
|
+
className: "mx-auto max-w-6xl",
|
|
1427
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1428
|
+
className: "card-subtle flex flex-col gap-6 p-8 md:flex-row md:items-center",
|
|
1429
|
+
children: [
|
|
1430
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1431
|
+
className: "flex-1 space-y-4",
|
|
1432
|
+
children: [
|
|
1433
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1434
|
+
className: "inline-flex items-center gap-2 rounded-full border border-violet-500/20 bg-violet-500/10 px-3 py-1",
|
|
1435
|
+
children: /* @__PURE__ */ jsxDEV3("span", {
|
|
1436
|
+
className: "text-sm font-medium text-violet-300",
|
|
1437
|
+
children: "Now accepting design partners"
|
|
1438
|
+
}, undefined, false, undefined, this)
|
|
1439
|
+
}, undefined, false, undefined, this),
|
|
1440
|
+
/* @__PURE__ */ jsxDEV3("h2", {
|
|
1441
|
+
className: "text-2xl font-bold",
|
|
1442
|
+
children: "Help us design the compiler for AI-native software."
|
|
1443
|
+
}, undefined, false, undefined, this),
|
|
1444
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1445
|
+
className: "text-muted-foreground text-sm",
|
|
1446
|
+
children: "We work closely with a small group of teams building serious products with AI. You bring real-world complexity, we bring the spec-first engine and a lot of attention."
|
|
1447
|
+
}, undefined, false, undefined, this)
|
|
1448
|
+
]
|
|
1449
|
+
}, undefined, true, undefined, this),
|
|
1450
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1451
|
+
className: "flex-1 space-y-4",
|
|
1452
|
+
children: [
|
|
1453
|
+
/* @__PURE__ */ jsxDEV3("ul", {
|
|
1454
|
+
className: "text-muted-foreground space-y-2 text-sm",
|
|
1455
|
+
children: [
|
|
1456
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1457
|
+
className: "flex gap-2",
|
|
1458
|
+
children: [
|
|
1459
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1460
|
+
size: 16,
|
|
1461
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1462
|
+
}, undefined, false, undefined, this),
|
|
1463
|
+
"Early access to ContractSpec Studio"
|
|
1464
|
+
]
|
|
1465
|
+
}, undefined, true, undefined, this),
|
|
1466
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1467
|
+
className: "flex gap-2",
|
|
1468
|
+
children: [
|
|
1469
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1470
|
+
size: 16,
|
|
1471
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1472
|
+
}, undefined, false, undefined, this),
|
|
1473
|
+
"Hands-on onboarding and architecture help"
|
|
1474
|
+
]
|
|
1475
|
+
}, undefined, true, undefined, this),
|
|
1476
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1477
|
+
className: "flex gap-2",
|
|
1478
|
+
children: [
|
|
1479
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1480
|
+
size: 16,
|
|
1481
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1482
|
+
}, undefined, false, undefined, this),
|
|
1483
|
+
"Influence over roadmap and features"
|
|
1484
|
+
]
|
|
1485
|
+
}, undefined, true, undefined, this),
|
|
1486
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1487
|
+
className: "flex gap-2",
|
|
1488
|
+
children: [
|
|
1489
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1490
|
+
size: 16,
|
|
1491
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1492
|
+
}, undefined, false, undefined, this),
|
|
1493
|
+
"Priority support during early access"
|
|
1494
|
+
]
|
|
1495
|
+
}, undefined, true, undefined, this),
|
|
1496
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1497
|
+
className: "flex gap-2",
|
|
1498
|
+
children: [
|
|
1499
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1500
|
+
size: 16,
|
|
1501
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1502
|
+
}, undefined, false, undefined, this),
|
|
1503
|
+
"Founding discount when paid plans launch"
|
|
1504
|
+
]
|
|
1505
|
+
}, undefined, true, undefined, this)
|
|
1506
|
+
]
|
|
1507
|
+
}, undefined, true, undefined, this),
|
|
1508
|
+
/* @__PURE__ */ jsxDEV3("button", {
|
|
1509
|
+
onClick: scrollToWaitlist,
|
|
1510
|
+
className: "btn-primary w-full md:w-auto",
|
|
1511
|
+
children: "Apply to the waitlist"
|
|
1512
|
+
}, undefined, false, undefined, this)
|
|
1513
|
+
]
|
|
1514
|
+
}, undefined, true, undefined, this)
|
|
1515
|
+
]
|
|
1516
|
+
}, undefined, true, undefined, this)
|
|
1517
|
+
}, undefined, false, undefined, this)
|
|
1518
|
+
}, undefined, false, undefined, this),
|
|
1519
|
+
/* @__PURE__ */ jsxDEV3("section", {
|
|
1520
|
+
className: "section-padding border-border border-b",
|
|
1521
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1522
|
+
className: "mx-auto max-w-6xl",
|
|
1523
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1524
|
+
className: "grid gap-6 md:grid-cols-3",
|
|
1525
|
+
children: [
|
|
1526
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1527
|
+
className: "card-subtle col-span-3 space-y-6 border-violet-500/20 p-6",
|
|
1528
|
+
children: [
|
|
1529
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1530
|
+
className: "absolute -top-3 left-1/2 -translate-x-1/2 rounded-full bg-violet-500 px-3 py-1 text-xs font-medium text-white",
|
|
1531
|
+
children: [
|
|
1532
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1533
|
+
className: "text-1xl font-bold",
|
|
1534
|
+
children: "Free Forever"
|
|
1535
|
+
}, undefined, false, undefined, this),
|
|
1536
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1537
|
+
className: "text-muted-foreground text-xs",
|
|
1538
|
+
children: "Apache 2.0 / MIT License"
|
|
1539
|
+
}, undefined, false, undefined, this)
|
|
1540
|
+
]
|
|
1541
|
+
}, undefined, true, undefined, this),
|
|
1542
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1543
|
+
className: "flex flex-row justify-around",
|
|
1544
|
+
children: [
|
|
1545
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1546
|
+
className: "w-1/2",
|
|
1547
|
+
children: [
|
|
1548
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1549
|
+
className: "space-y-2",
|
|
1550
|
+
children: /* @__PURE__ */ jsxDEV3("h2", {
|
|
1551
|
+
className: "text-2xl font-bold",
|
|
1552
|
+
children: "OSS Core"
|
|
1553
|
+
}, undefined, false, undefined, this)
|
|
1554
|
+
}, undefined, false, undefined, this),
|
|
1555
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1556
|
+
className: "text-muted-foreground text-sm",
|
|
1557
|
+
children: "The complete spec-first compiler. Generate API, DB, and UI code locally."
|
|
1558
|
+
}, undefined, false, undefined, this)
|
|
1559
|
+
]
|
|
1560
|
+
}, undefined, true, undefined, this),
|
|
1561
|
+
/* @__PURE__ */ jsxDEV3("ul", {
|
|
1562
|
+
className: "space-y-3",
|
|
1563
|
+
children: [
|
|
1564
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1565
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1566
|
+
children: [
|
|
1567
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1568
|
+
size: 16,
|
|
1569
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1570
|
+
}, undefined, false, undefined, this),
|
|
1571
|
+
"Unlimited local regenerations"
|
|
1572
|
+
]
|
|
1573
|
+
}, undefined, true, undefined, this),
|
|
1574
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1575
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1576
|
+
children: [
|
|
1577
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1578
|
+
size: 16,
|
|
1579
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1580
|
+
}, undefined, false, undefined, this),
|
|
1581
|
+
"All standard generators included"
|
|
1582
|
+
]
|
|
1583
|
+
}, undefined, true, undefined, this),
|
|
1584
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1585
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1586
|
+
children: [
|
|
1587
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1588
|
+
size: 16,
|
|
1589
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1590
|
+
}, undefined, false, undefined, this),
|
|
1591
|
+
"Run in your own CI/CD"
|
|
1592
|
+
]
|
|
1593
|
+
}, undefined, true, undefined, this),
|
|
1594
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1595
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1596
|
+
children: [
|
|
1597
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1598
|
+
size: 16,
|
|
1599
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1600
|
+
}, undefined, false, undefined, this),
|
|
1601
|
+
"Community support"
|
|
1602
|
+
]
|
|
1603
|
+
}, undefined, true, undefined, this)
|
|
1604
|
+
]
|
|
1605
|
+
}, undefined, true, undefined, this)
|
|
1606
|
+
]
|
|
1607
|
+
}, undefined, true, undefined, this),
|
|
1608
|
+
/* @__PURE__ */ jsxDEV3(Link, {
|
|
1609
|
+
href: "/install",
|
|
1610
|
+
className: "btn-ghost w-full",
|
|
1611
|
+
children: "Install now"
|
|
1612
|
+
}, undefined, false, undefined, this)
|
|
1613
|
+
]
|
|
1614
|
+
}, undefined, true, undefined, this),
|
|
1615
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1616
|
+
className: "card-subtle relative space-y-6 bg-violet-500/5 p-6 ring-2 ring-violet-500",
|
|
1617
|
+
children: [
|
|
1618
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1619
|
+
className: "absolute -top-3 left-1/2 -translate-x-1/2 rounded-full bg-violet-500 px-3 py-1 text-xs font-medium text-white",
|
|
1620
|
+
children: "Current"
|
|
1621
|
+
}, undefined, false, undefined, this),
|
|
1622
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1623
|
+
className: "space-y-2",
|
|
1624
|
+
children: [
|
|
1625
|
+
/* @__PURE__ */ jsxDEV3("h2", {
|
|
1626
|
+
className: "text-2xl font-bold",
|
|
1627
|
+
children: "Design Partner"
|
|
1628
|
+
}, undefined, false, undefined, this),
|
|
1629
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1630
|
+
className: "space-y-1",
|
|
1631
|
+
children: [
|
|
1632
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1633
|
+
className: "text-2xl font-bold",
|
|
1634
|
+
children: "Free during early access"
|
|
1635
|
+
}, undefined, false, undefined, this),
|
|
1636
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1637
|
+
className: "text-muted-foreground text-xs",
|
|
1638
|
+
children: "Founding discount when paid plans launch"
|
|
1639
|
+
}, undefined, false, undefined, this)
|
|
1640
|
+
]
|
|
1641
|
+
}, undefined, true, undefined, this)
|
|
1642
|
+
]
|
|
1643
|
+
}, undefined, true, undefined, this),
|
|
1644
|
+
/* @__PURE__ */ jsxDEV3("ul", {
|
|
1645
|
+
className: "space-y-3",
|
|
1646
|
+
children: [
|
|
1647
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1648
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1649
|
+
children: [
|
|
1650
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1651
|
+
size: 16,
|
|
1652
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1653
|
+
}, undefined, false, undefined, this),
|
|
1654
|
+
"Use ContractSpec Studio for real projects during early access"
|
|
1655
|
+
]
|
|
1656
|
+
}, undefined, true, undefined, this),
|
|
1657
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1658
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1659
|
+
children: [
|
|
1660
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1661
|
+
size: 16,
|
|
1662
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1663
|
+
}, undefined, false, undefined, this),
|
|
1664
|
+
"Work directly with the founder on architecture & use cases"
|
|
1665
|
+
]
|
|
1666
|
+
}, undefined, true, undefined, this),
|
|
1667
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1668
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1669
|
+
children: [
|
|
1670
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1671
|
+
size: 16,
|
|
1672
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1673
|
+
}, undefined, false, undefined, this),
|
|
1674
|
+
'Reasonable "fair use" limits on regenerations and AI credits'
|
|
1675
|
+
]
|
|
1676
|
+
}, undefined, true, undefined, this),
|
|
1677
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1678
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1679
|
+
children: [
|
|
1680
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1681
|
+
size: 16,
|
|
1682
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1683
|
+
}, undefined, false, undefined, this),
|
|
1684
|
+
"Priority support & feedback loops"
|
|
1685
|
+
]
|
|
1686
|
+
}, undefined, true, undefined, this)
|
|
1687
|
+
]
|
|
1688
|
+
}, undefined, true, undefined, this),
|
|
1689
|
+
/* @__PURE__ */ jsxDEV3("button", {
|
|
1690
|
+
onClick: scrollToWaitlist,
|
|
1691
|
+
className: "btn-primary w-full",
|
|
1692
|
+
children: "Apply as a design partner"
|
|
1693
|
+
}, undefined, false, undefined, this)
|
|
1694
|
+
]
|
|
1695
|
+
}, undefined, true, undefined, this),
|
|
1696
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1697
|
+
className: "card-subtle relative space-y-6 p-6",
|
|
1698
|
+
children: [
|
|
1699
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1700
|
+
className: "bg-muted border-border absolute -top-3 left-1/2 -translate-x-1/2 rounded-full border px-3 py-1 text-xs font-medium",
|
|
1701
|
+
children: "Coming soon"
|
|
1702
|
+
}, undefined, false, undefined, this),
|
|
1703
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1704
|
+
className: "space-y-2",
|
|
1705
|
+
children: [
|
|
1706
|
+
/* @__PURE__ */ jsxDEV3("h2", {
|
|
1707
|
+
className: "text-2xl font-bold",
|
|
1708
|
+
children: "Builder"
|
|
1709
|
+
}, undefined, false, undefined, this),
|
|
1710
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1711
|
+
className: "space-y-1",
|
|
1712
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1713
|
+
className: "text-2xl font-bold",
|
|
1714
|
+
children: "Usage-based, for solo builders and small teams"
|
|
1715
|
+
}, undefined, false, undefined, this)
|
|
1716
|
+
}, undefined, false, undefined, this)
|
|
1717
|
+
]
|
|
1718
|
+
}, undefined, true, undefined, this),
|
|
1719
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1720
|
+
className: "text-muted-foreground text-sm",
|
|
1721
|
+
children: "Pay only for what you regenerate and the AI you consume. No seat-based pricing, and a generous free tier for experiments."
|
|
1722
|
+
}, undefined, false, undefined, this),
|
|
1723
|
+
/* @__PURE__ */ jsxDEV3("ul", {
|
|
1724
|
+
className: "space-y-2",
|
|
1725
|
+
children: [
|
|
1726
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1727
|
+
className: "text-muted-foreground text-sm",
|
|
1728
|
+
children: "1–3 projects"
|
|
1729
|
+
}, undefined, false, undefined, this),
|
|
1730
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1731
|
+
className: "text-muted-foreground text-sm",
|
|
1732
|
+
children: "Generous monthly free regenerations"
|
|
1733
|
+
}, undefined, false, undefined, this),
|
|
1734
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1735
|
+
className: "text-muted-foreground text-sm",
|
|
1736
|
+
children: "Pay-as-you-go beyond the free tier"
|
|
1737
|
+
}, undefined, false, undefined, this)
|
|
1738
|
+
]
|
|
1739
|
+
}, undefined, true, undefined, this),
|
|
1740
|
+
/* @__PURE__ */ jsxDEV3("button", {
|
|
1741
|
+
disabled: true,
|
|
1742
|
+
className: "btn-ghost w-full cursor-not-allowed opacity-50",
|
|
1743
|
+
children: "Available after public launch"
|
|
1744
|
+
}, undefined, false, undefined, this)
|
|
1745
|
+
]
|
|
1746
|
+
}, undefined, true, undefined, this),
|
|
1747
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1748
|
+
className: "card-subtle relative space-y-6 p-6",
|
|
1749
|
+
children: [
|
|
1750
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1751
|
+
className: "bg-muted border-border absolute -top-3 left-1/2 -translate-x-1/2 rounded-full border px-3 py-1 text-xs font-medium",
|
|
1752
|
+
children: "Coming soon"
|
|
1753
|
+
}, undefined, false, undefined, this),
|
|
1754
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1755
|
+
className: "space-y-2",
|
|
1756
|
+
children: [
|
|
1757
|
+
/* @__PURE__ */ jsxDEV3("h2", {
|
|
1758
|
+
className: "text-2xl font-bold",
|
|
1759
|
+
children: "Team & Platform"
|
|
1760
|
+
}, undefined, false, undefined, this),
|
|
1761
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1762
|
+
className: "space-y-1",
|
|
1763
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1764
|
+
className: "text-2xl font-bold",
|
|
1765
|
+
children: "Custom, for teams standardizing on ContractSpec"
|
|
1766
|
+
}, undefined, false, undefined, this)
|
|
1767
|
+
}, undefined, false, undefined, this)
|
|
1768
|
+
]
|
|
1769
|
+
}, undefined, true, undefined, this),
|
|
1770
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1771
|
+
className: "text-muted-foreground text-sm",
|
|
1772
|
+
children: "For teams running multiple apps or platforms on ContractSpec, with stricter governance, data, and compliance needs."
|
|
1773
|
+
}, undefined, false, undefined, this),
|
|
1774
|
+
/* @__PURE__ */ jsxDEV3("ul", {
|
|
1775
|
+
className: "space-y-3",
|
|
1776
|
+
children: [
|
|
1777
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1778
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1779
|
+
children: [
|
|
1780
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1781
|
+
size: 16,
|
|
1782
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1783
|
+
}, undefined, false, undefined, this),
|
|
1784
|
+
"Multiple projects and environments"
|
|
1785
|
+
]
|
|
1786
|
+
}, undefined, true, undefined, this),
|
|
1787
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1788
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1789
|
+
children: [
|
|
1790
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1791
|
+
size: 16,
|
|
1792
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1793
|
+
}, undefined, false, undefined, this),
|
|
1794
|
+
"Advanced RBAC and policy packs"
|
|
1795
|
+
]
|
|
1796
|
+
}, undefined, true, undefined, this),
|
|
1797
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1798
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1799
|
+
children: [
|
|
1800
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1801
|
+
size: 16,
|
|
1802
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1803
|
+
}, undefined, false, undefined, this),
|
|
1804
|
+
"SSO, audit trails, and longer retention"
|
|
1805
|
+
]
|
|
1806
|
+
}, undefined, true, undefined, this),
|
|
1807
|
+
/* @__PURE__ */ jsxDEV3("li", {
|
|
1808
|
+
className: "text-muted-foreground flex gap-3 text-sm",
|
|
1809
|
+
children: [
|
|
1810
|
+
/* @__PURE__ */ jsxDEV3(CheckCircle3, {
|
|
1811
|
+
size: 16,
|
|
1812
|
+
className: "mt-0.5 shrink-0 text-violet-400"
|
|
1813
|
+
}, undefined, false, undefined, this),
|
|
1814
|
+
"Priority support & SLAs"
|
|
1815
|
+
]
|
|
1816
|
+
}, undefined, true, undefined, this)
|
|
1817
|
+
]
|
|
1818
|
+
}, undefined, true, undefined, this),
|
|
1819
|
+
/* @__PURE__ */ jsxDEV3(Link, {
|
|
1820
|
+
href: "/contact",
|
|
1821
|
+
className: "btn-ghost w-full",
|
|
1822
|
+
children: "Talk to us"
|
|
1823
|
+
}, undefined, false, undefined, this)
|
|
1824
|
+
]
|
|
1825
|
+
}, undefined, true, undefined, this)
|
|
1826
|
+
]
|
|
1827
|
+
}, undefined, true, undefined, this)
|
|
1828
|
+
}, undefined, false, undefined, this)
|
|
1829
|
+
}, undefined, false, undefined, this),
|
|
1830
|
+
/* @__PURE__ */ jsxDEV3("section", {
|
|
1831
|
+
className: "section-padding border-border bg-muted/20 border-b",
|
|
1832
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1833
|
+
className: "mx-auto max-w-4xl space-y-8",
|
|
1834
|
+
children: [
|
|
1835
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1836
|
+
className: "space-y-4 text-center",
|
|
1837
|
+
children: [
|
|
1838
|
+
/* @__PURE__ */ jsxDEV3("h2", {
|
|
1839
|
+
className: "text-3xl font-bold",
|
|
1840
|
+
children: "How ContractSpec pricing will work"
|
|
1841
|
+
}, undefined, false, undefined, this),
|
|
1842
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1843
|
+
className: "text-muted-foreground mx-auto max-w-2xl text-lg",
|
|
1844
|
+
children: "We charge based on how much of your stack we help you maintain, not how many people click around in the UI."
|
|
1845
|
+
}, undefined, false, undefined, this)
|
|
1846
|
+
]
|
|
1847
|
+
}, undefined, true, undefined, this),
|
|
1848
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1849
|
+
className: "grid gap-6 md:grid-cols-3",
|
|
1850
|
+
children: [
|
|
1851
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1852
|
+
className: "card-subtle space-y-3 p-6",
|
|
1853
|
+
children: [
|
|
1854
|
+
/* @__PURE__ */ jsxDEV3("h3", {
|
|
1855
|
+
className: "font-bold",
|
|
1856
|
+
children: "Generous free tier"
|
|
1857
|
+
}, undefined, false, undefined, this),
|
|
1858
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1859
|
+
className: "text-muted-foreground text-sm",
|
|
1860
|
+
children: "One serious project, small spec, and enough monthly regenerations to ship something real."
|
|
1861
|
+
}, undefined, false, undefined, this)
|
|
1862
|
+
]
|
|
1863
|
+
}, undefined, true, undefined, this),
|
|
1864
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1865
|
+
className: "card-subtle space-y-3 p-6",
|
|
1866
|
+
children: [
|
|
1867
|
+
/* @__PURE__ */ jsxDEV3("h3", {
|
|
1868
|
+
className: "font-bold",
|
|
1869
|
+
children: "Usage-based beyond free"
|
|
1870
|
+
}, undefined, false, undefined, this),
|
|
1871
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1872
|
+
className: "text-muted-foreground text-sm",
|
|
1873
|
+
children: "You pay for regenerations and AI agent actions, not per-seat. The more your system evolves via ContractSpec, the more you pay."
|
|
1874
|
+
}, undefined, false, undefined, this)
|
|
1875
|
+
]
|
|
1876
|
+
}, undefined, true, undefined, this),
|
|
1877
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1878
|
+
className: "card-subtle space-y-3 p-6",
|
|
1879
|
+
children: [
|
|
1880
|
+
/* @__PURE__ */ jsxDEV3("h3", {
|
|
1881
|
+
className: "font-bold",
|
|
1882
|
+
children: "No lock-in"
|
|
1883
|
+
}, undefined, false, undefined, this),
|
|
1884
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1885
|
+
className: "text-muted-foreground text-sm",
|
|
1886
|
+
children: "Generated code is standard, readable, and exportable. If you leave, your app keeps running."
|
|
1887
|
+
}, undefined, false, undefined, this)
|
|
1888
|
+
]
|
|
1889
|
+
}, undefined, true, undefined, this)
|
|
1890
|
+
]
|
|
1891
|
+
}, undefined, true, undefined, this),
|
|
1892
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1893
|
+
className: "pt-6 text-center",
|
|
1894
|
+
children: /* @__PURE__ */ jsxDEV3("button", {
|
|
1895
|
+
onClick: () => setPricingModalOpen(true),
|
|
1896
|
+
className: "btn-ghost",
|
|
1897
|
+
children: "View our tentative pricing model"
|
|
1898
|
+
}, undefined, false, undefined, this)
|
|
1899
|
+
}, undefined, false, undefined, this)
|
|
1900
|
+
]
|
|
1901
|
+
}, undefined, true, undefined, this)
|
|
1902
|
+
}, undefined, false, undefined, this),
|
|
1903
|
+
/* @__PURE__ */ jsxDEV3("section", {
|
|
1904
|
+
className: "section-padding border-border border-b",
|
|
1905
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1906
|
+
className: "mx-auto max-w-3xl space-y-8",
|
|
1907
|
+
children: [
|
|
1908
|
+
/* @__PURE__ */ jsxDEV3("h2", {
|
|
1909
|
+
className: "text-center text-3xl font-bold",
|
|
1910
|
+
children: "Frequently asked questions"
|
|
1911
|
+
}, undefined, false, undefined, this),
|
|
1912
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1913
|
+
className: "space-y-4",
|
|
1914
|
+
children: faqs.map((faq, i) => /* @__PURE__ */ jsxDEV3("div", {
|
|
1915
|
+
className: "card-subtle overflow-hidden",
|
|
1916
|
+
children: [
|
|
1917
|
+
/* @__PURE__ */ jsxDEV3("button", {
|
|
1918
|
+
onClick: () => setOpenFaq(openFaq === i ? null : i),
|
|
1919
|
+
className: "flex w-full items-center justify-between p-6 text-left",
|
|
1920
|
+
children: [
|
|
1921
|
+
/* @__PURE__ */ jsxDEV3("span", {
|
|
1922
|
+
className: "font-medium",
|
|
1923
|
+
children: faq.question
|
|
1924
|
+
}, undefined, false, undefined, this),
|
|
1925
|
+
/* @__PURE__ */ jsxDEV3(ChevronDown, {
|
|
1926
|
+
size: 20,
|
|
1927
|
+
className: `text-muted-foreground transition-transform ${openFaq === i ? "rotate-180" : ""}`
|
|
1928
|
+
}, undefined, false, undefined, this)
|
|
1929
|
+
]
|
|
1930
|
+
}, undefined, true, undefined, this),
|
|
1931
|
+
openFaq === i && /* @__PURE__ */ jsxDEV3("div", {
|
|
1932
|
+
className: "text-muted-foreground px-6 pb-6 text-sm",
|
|
1933
|
+
children: faq.answer
|
|
1934
|
+
}, undefined, false, undefined, this)
|
|
1935
|
+
]
|
|
1936
|
+
}, i, true, undefined, this))
|
|
1937
|
+
}, undefined, false, undefined, this),
|
|
1938
|
+
/* @__PURE__ */ jsxDEV3("div", {
|
|
1939
|
+
className: "pt-4 text-center",
|
|
1940
|
+
children: [
|
|
1941
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
1942
|
+
className: "text-muted-foreground mb-2 text-sm",
|
|
1943
|
+
children: "Still unsure?"
|
|
1944
|
+
}, undefined, false, undefined, this),
|
|
1945
|
+
/* @__PURE__ */ jsxDEV3(Link, {
|
|
1946
|
+
href: "/contact",
|
|
1947
|
+
className: "text-sm font-medium text-violet-400 hover:text-violet-300",
|
|
1948
|
+
children: "Contact us →"
|
|
1949
|
+
}, undefined, false, undefined, this)
|
|
1950
|
+
]
|
|
1951
|
+
}, undefined, true, undefined, this)
|
|
1952
|
+
]
|
|
1953
|
+
}, undefined, true, undefined, this)
|
|
1954
|
+
}, undefined, false, undefined, this),
|
|
1955
|
+
/* @__PURE__ */ jsxDEV3("section", {
|
|
1956
|
+
className: "section-padding hero-gradient",
|
|
1957
|
+
children: /* @__PURE__ */ jsxDEV3("div", {
|
|
1958
|
+
className: "mx-auto max-w-4xl",
|
|
1959
|
+
children: /* @__PURE__ */ jsxDEV3(WaitlistSection, {}, undefined, false, undefined, this)
|
|
1960
|
+
}, undefined, false, undefined, this)
|
|
1961
|
+
}, undefined, false, undefined, this),
|
|
1962
|
+
/* @__PURE__ */ jsxDEV3(PricingThinkingModal, {
|
|
1963
|
+
open: pricingModalOpen,
|
|
1964
|
+
onOpenChange: setPricingModalOpen,
|
|
1965
|
+
onApplyClick: scrollToWaitlist
|
|
1966
|
+
}, undefined, false, undefined, this)
|
|
1967
|
+
]
|
|
1968
|
+
}, undefined, true, undefined, this);
|
|
1969
|
+
}
|
|
1970
|
+
export {
|
|
1971
|
+
PricingClient
|
|
1972
|
+
};
|