Skip to content

Commit a26ff59

Browse files
feat(web): add shareable stack page (#556)
1 parent e8ccc07 commit a26ff59

File tree

17 files changed

+1894
-422
lines changed

17 files changed

+1894
-422
lines changed

apps/cli/src/prompts/config-prompts.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -123,25 +123,6 @@ export async function gatherConfig(
123123
},
124124
);
125125

126-
if (result.backend === "convex") {
127-
result.runtime = "none";
128-
result.database = "none";
129-
result.orm = "none";
130-
result.api = "none";
131-
result.dbSetup = "none";
132-
result.examples = ["todo"];
133-
}
134-
135-
if (result.backend === "none") {
136-
result.runtime = "none";
137-
result.database = "none";
138-
result.orm = "none";
139-
result.api = "none";
140-
result.auth = "none";
141-
result.dbSetup = "none";
142-
result.examples = [];
143-
}
144-
145126
return {
146127
projectName: projectName,
147128
projectDir: projectDir,

apps/cli/src/utils/config-validation.ts

Lines changed: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,116 @@ export function validateDatabaseSetup(
175175
}
176176
}
177177

178+
export function validateConvexConstraints(
179+
config: Partial<ProjectConfig>,
180+
providedFlags: Set<string>,
181+
): void {
182+
const { backend } = config;
183+
184+
if (backend !== "convex") {
185+
return;
186+
}
187+
188+
const has = (k: string) => providedFlags.has(k);
189+
190+
if (has("runtime") && config.runtime !== "none") {
191+
exitWithError(
192+
"Convex backend requires '--runtime none'. Please remove the --runtime flag or set it to 'none'.",
193+
);
194+
}
195+
196+
if (has("database") && config.database !== "none") {
197+
exitWithError(
198+
"Convex backend requires '--database none'. Please remove the --database flag or set it to 'none'.",
199+
);
200+
}
201+
202+
if (has("orm") && config.orm !== "none") {
203+
exitWithError(
204+
"Convex backend requires '--orm none'. Please remove the --orm flag or set it to 'none'.",
205+
);
206+
}
207+
208+
if (has("api") && config.api !== "none") {
209+
exitWithError(
210+
"Convex backend requires '--api none'. Please remove the --api flag or set it to 'none'.",
211+
);
212+
}
213+
214+
if (has("dbSetup") && config.dbSetup !== "none") {
215+
exitWithError(
216+
"Convex backend requires '--db-setup none'. Please remove the --db-setup flag or set it to 'none'.",
217+
);
218+
}
219+
220+
if (has("serverDeploy") && config.serverDeploy !== "none") {
221+
exitWithError(
222+
"Convex backend requires '--server-deploy none'. Please remove the --server-deploy flag or set it to 'none'.",
223+
);
224+
}
225+
226+
if (has("auth") && config.auth === "better-auth") {
227+
exitWithError(
228+
"Better-Auth is not compatible with Convex backend. Please use '--auth clerk' or '--auth none'.",
229+
);
230+
}
231+
}
232+
233+
export function validateBackendNoneConstraints(
234+
config: Partial<ProjectConfig>,
235+
providedFlags: Set<string>,
236+
): void {
237+
const { backend } = config;
238+
239+
if (backend !== "none") {
240+
return;
241+
}
242+
243+
const has = (k: string) => providedFlags.has(k);
244+
245+
if (has("runtime") && config.runtime !== "none") {
246+
exitWithError(
247+
"Backend 'none' requires '--runtime none'. Please remove the --runtime flag or set it to 'none'.",
248+
);
249+
}
250+
251+
if (has("database") && config.database !== "none") {
252+
exitWithError(
253+
"Backend 'none' requires '--database none'. Please remove the --database flag or set it to 'none'.",
254+
);
255+
}
256+
257+
if (has("orm") && config.orm !== "none") {
258+
exitWithError(
259+
"Backend 'none' requires '--orm none'. Please remove the --orm flag or set it to 'none'.",
260+
);
261+
}
262+
263+
if (has("api") && config.api !== "none") {
264+
exitWithError(
265+
"Backend 'none' requires '--api none'. Please remove the --api flag or set it to 'none'.",
266+
);
267+
}
268+
269+
if (has("auth") && config.auth !== "none") {
270+
exitWithError(
271+
"Backend 'none' requires '--auth none'. Please remove the --auth flag or set it to 'none'.",
272+
);
273+
}
274+
275+
if (has("dbSetup") && config.dbSetup !== "none") {
276+
exitWithError(
277+
"Backend 'none' requires '--db-setup none'. Please remove the --db-setup flag or set it to 'none'.",
278+
);
279+
}
280+
281+
if (has("serverDeploy") && config.serverDeploy !== "none") {
282+
exitWithError(
283+
"Backend 'none' requires '--server-deploy none'. Please remove the --server-deploy flag or set it to 'none'.",
284+
);
285+
}
286+
}
287+
178288
export function validateBackendConstraints(
179289
config: Partial<ProjectConfig>,
180290
providedFlags: Set<string>,
@@ -201,16 +311,6 @@ export function validateBackendConstraints(
201311
}
202312
}
203313

204-
if (
205-
backend === "convex" &&
206-
config.auth === "better-auth" &&
207-
providedFlags.has("auth")
208-
) {
209-
exitWithError(
210-
"Better-Auth is not compatible with the Convex backend. Please use '--auth clerk' or '--auth none'.",
211-
);
212-
}
213-
214314
if (
215315
providedFlags.has("backend") &&
216316
backend &&
@@ -287,6 +387,8 @@ export function validateFullConfig(
287387
validateDatabaseOrmAuth(config, providedFlags);
288388
validateDatabaseSetup(config, providedFlags);
289389

390+
validateConvexConstraints(config, providedFlags);
391+
validateBackendNoneConstraints(config, providedFlags);
290392
validateBackendConstraints(config, providedFlags, options);
291393

292394
validateFrontendConstraints(config, providedFlags);

apps/web/lib/cn.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

apps/web/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"clsx": "^2.1.1",
2828
"convex": "^1.25.4",
2929
"convex-helpers": "^0.1.104",
30+
"culori": "^4.0.2",
3031
"date-fns": "^4.1.0",
3132
"fumadocs-core": "15.6.7",
3233
"fumadocs-mdx": "11.7.3",
@@ -38,6 +39,7 @@
3839
"nuqs": "^2.4.3",
3940
"papaparse": "^5.5.3",
4041
"posthog-js": "^1.258.5",
42+
"qrcode": "^1.5.4",
4143
"radix-ui": "^1.4.2",
4244
"react": "^19.1.1",
4345
"react-dom": "^19.1.1",
@@ -52,9 +54,11 @@
5254
},
5355
"devDependencies": {
5456
"@tailwindcss/postcss": "^4.1.11",
57+
"@types/culori": "^4.0.0",
5558
"@types/mdx": "^2.0.13",
5659
"@types/node": "24.1.0",
5760
"@types/papaparse": "^5.3.16",
61+
"@types/qrcode": "^1.5.5",
5862
"@types/react": "^19.1.9",
5963
"@types/react-dom": "^19.1.7",
6064
"eslint": "^9.32.0",

apps/web/scripts/generate-analytics.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -242,23 +242,19 @@ async function generateAnalyticsData() {
242242
cliVersionCounts[cliVersion] =
243243
(cliVersionCounts[cliVersion] || 0) + 1;
244244

245-
// Auth
246245
const auth =
247246
row["*.properties.auth"] === "True" ? "enabled" : "disabled";
248247
authCounts[auth] = (authCounts[auth] || 0) + 1;
249248
if (auth === "enabled") authEnabledCount++;
250249

251-
// Git
252250
const git =
253251
row["*.properties.git"] === "True" ? "enabled" : "disabled";
254252
gitCounts[git] = (gitCounts[git] || 0) + 1;
255253

256-
// Install
257254
const install =
258255
row["*.properties.install"] === "True" ? "enabled" : "disabled";
259256
installCounts[install] = (installCounts[install] || 0) + 1;
260257

261-
// Examples
262258
const examples = [
263259
row["*.properties.examples.0"],
264260
row["*.properties.examples.1"],
@@ -271,7 +267,6 @@ async function generateAnalyticsData() {
271267
}
272268
}
273269

274-
// Addons
275270
const addons = [
276271
row["*.properties.addons.0"],
277272
row["*.properties.addons.1"],
@@ -288,23 +283,19 @@ async function generateAnalyticsData() {
288283
}
289284
}
290285

291-
// Runtime
292286
const runtime = row["*.properties.runtime"] || "unknown";
293287
runtimeCounts[runtime] = (runtimeCounts[runtime] || 0) + 1;
294288

295-
// Web Deploy (migrate "workers" to "wrangler")
296289
const webDeploy = row["*.properties.webDeploy"] || "none";
297290
const normalizedWebDeploy =
298291
webDeploy === "workers" ? "wrangler" : webDeploy;
299292
webDeployCounts[normalizedWebDeploy] =
300293
(webDeployCounts[normalizedWebDeploy] || 0) + 1;
301294

302-
// Server Deploy
303295
const serverDeploy = row["*.properties.serverDeploy"] || "none";
304296
serverDeployCounts[serverDeploy] =
305297
(serverDeployCounts[serverDeploy] || 0) + 1;
306298

307-
// Project type
308299
const hasFrontend =
309300
(frontend0 && frontend0 !== "none") ||
310301
(frontend1 && frontend1 !== "none");
@@ -321,7 +312,6 @@ async function generateAnalyticsData() {
321312
}
322313
projectTypeCounts[type] = (projectTypeCounts[type] || 0) + 1;
323314

324-
// Stack combinations
325315
const frontends = [frontend0, frontend1].filter(
326316
(f) => f && f !== "none" && f !== "",
327317
);
@@ -332,7 +322,6 @@ async function generateAnalyticsData() {
332322
const combo = parts.length > 0 ? parts.join(" + ") : "none";
333323
stackComboCounts[combo] = (stackComboCounts[combo] || 0) + 1;
334324

335-
// Database + ORM combinations
336325
if (database !== "none" && orm !== "none") {
337326
const combo = `${database} + ${orm}`;
338327
dbORMComboCounts[combo] = (dbORMComboCounts[combo] || 0) + 1;

0 commit comments

Comments
 (0)