$
@@ -1084,77 +1316,7 @@ const StackArchitect = () => {
-
- {CATEGORY_ORDER.flatMap((category) => {
- const categoryKey = category as keyof StackState;
- const options =
- TECH_OPTIONS[category as keyof typeof TECH_OPTIONS];
- const selectedValue = stack[categoryKey];
-
- if (!options) return [];
-
- if (Array.isArray(selectedValue)) {
- if (selectedValue.length === 0 || selectedValue[0] === "none")
- return [];
-
- return selectedValue
- .map((id) => options.find((opt) => opt.id === id))
- .filter((tech): tech is NonNullable =>
- Boolean(tech),
- )
- .map((tech) => (
-
-
- {tech.name}
-
- ));
- }
- const tech = options.find((opt) => opt.id === selectedValue);
-
- if (
- !tech ||
- tech.id === "none" ||
- tech.id === "false" ||
- ((category === "git" ||
- category === "install" ||
- category === "auth") &&
- tech.id === "true")
- ) {
- return [];
- }
-
- return (
-
-
- {tech.name}
-
- );
- })}
-
+
{selectedBadges}
@@ -1192,6 +1354,35 @@ const StackArchitect = () => {
TECH_OPTIONS[categoryKey as keyof typeof TECH_OPTIONS] || [];
const categoryDisplayName = getCategoryDisplayName(categoryKey);
+ const filteredOptions = categoryOptions.filter((tech) => {
+ if (
+ isConvexSelected &&
+ tech.id === "none" &&
+ ["runtime", "database", "orm", "api", "dbSetup"].includes(
+ categoryKey,
+ )
+ ) {
+ return false;
+ }
+ if (
+ isConvexSelected &&
+ categoryKey === "auth" &&
+ tech.id === "false"
+ ) {
+ return false;
+ }
+ if (
+ isConvexSelected &&
+ categoryKey === "examples" &&
+ tech.id !== "todo"
+ ) {
+ return false;
+ }
+ return true;
+ });
+
+ if (filteredOptions.length === 0) return null;
+
return (
{
@@ -1226,7 +1417,7 @@ const StackArchitect = () => {
- {categoryOptions.map((tech) => {
+ {filteredOptions.map((tech) => {
let isSelected = false;
const category = categoryKey as keyof StackState;
@@ -1242,12 +1433,10 @@ const StackArchitect = () => {
isSelected = stack[category] === tech.id;
}
- const disabledReason = getDisabledReason(
- categoryKey as keyof typeof TECH_OPTIONS,
- tech.id,
+ const disabledReason = disabledReasons.get(
+ `${categoryKey}-${tech.id}`,
);
-
- const isDisabled = !!disabledReason && !isSelected;
+ const isDisabled = !!disabledReason;
return (
@@ -1255,7 +1444,7 @@ const StackArchitect = () => {
{
{tech.name}
- {isDisabled && (
+ {isDisabled && !isSelected && (
)}
diff --git a/apps/web/src/lib/constant.ts b/apps/web/src/lib/constant.ts
index d25c3e6..485ab25 100644
--- a/apps/web/src/lib/constant.ts
+++ b/apps/web/src/lib/constant.ts
@@ -100,7 +100,7 @@ export const TECH_OPTIONS = {
color: "from-green-400 to-green-600",
},
],
- backendFramework: [
+ backend: [
{
id: "hono",
name: "Hono",
@@ -130,6 +130,13 @@ export const TECH_OPTIONS = {
icon: "/icon/express.svg",
color: "from-gray-500 to-gray-700",
},
+ {
+ id: "convex",
+ name: "Convex",
+ description: "Reactive backend-as-a-service",
+ icon: "/icon/convex.svg",
+ color: "from-pink-500 to-pink-700",
+ },
],
database: [
{
@@ -385,7 +392,7 @@ export const PRESET_TEMPLATES = [
projectName: "my-better-t-app",
frontend: ["tanstack-router"],
runtime: "bun",
- backendFramework: "hono",
+ backend: "hono",
database: "sqlite",
orm: "drizzle",
dbSetup: "none",
@@ -398,15 +405,36 @@ export const PRESET_TEMPLATES = [
api: "trpc",
},
},
+ {
+ id: "convex-react",
+ name: "Convex + React",
+ description: "Reactive full-stack app with Convex and TanStack Router",
+ stack: {
+ projectName: "my-convex-app",
+ frontend: ["tanstack-router"],
+ backend: "convex",
+ runtime: "none",
+ database: "none",
+ orm: "none",
+ dbSetup: "none",
+ auth: "false",
+ packageManager: "bun",
+ addons: [],
+ examples: ["todo"],
+ git: "true",
+ install: "true",
+ api: "none",
+ },
+ },
{
id: "native-app",
name: "Mobile App",
description: "React Native with Expo and SQLite database",
stack: {
- projectName: "my-better-t-app",
+ projectName: "my-native-app",
frontend: ["native"],
runtime: "bun",
- backendFramework: "hono",
+ backend: "hono",
database: "sqlite",
orm: "drizzle",
dbSetup: "none",
@@ -424,10 +452,10 @@ export const PRESET_TEMPLATES = [
name: "API Only",
description: "Backend API with Hono and PostgreSQL",
stack: {
- projectName: "my-better-t-app",
+ projectName: "my-api",
frontend: ["none"],
runtime: "bun",
- backendFramework: "hono",
+ backend: "hono",
database: "postgres",
orm: "drizzle",
dbSetup: "none",
@@ -443,12 +471,12 @@ export const PRESET_TEMPLATES = [
{
id: "full-featured",
name: "Full Featured",
- description: "Complete setup with all the bells and whistles",
+ description: "Complete setup with web, native, Turso, and addons",
stack: {
- projectName: "my-better-t-app",
+ projectName: "my-full-app",
frontend: ["tanstack-router", "native"],
runtime: "bun",
- backendFramework: "hono",
+ backend: "hono",
database: "sqlite",
orm: "drizzle",
dbSetup: "turso",
@@ -467,7 +495,7 @@ export type StackState = {
projectName: string;
frontend: string[];
runtime: string;
- backendFramework: string;
+ backend: string;
database: string;
orm: string;
dbSetup: string;
@@ -484,7 +512,7 @@ export const DEFAULT_STACK: StackState = {
projectName: "my-better-t-app",
frontend: ["tanstack-router"],
runtime: "bun",
- backendFramework: "hono",
+ backend: "hono",
database: "sqlite",
orm: "drizzle",
dbSetup: "none",
diff --git a/apps/web/src/lib/stack-url-state.ts b/apps/web/src/lib/stack-url-state.ts
index dd630d8..a9dac72 100644
--- a/apps/web/src/lib/stack-url-state.ts
+++ b/apps/web/src/lib/stack-url-state.ts
@@ -16,9 +16,9 @@ export const stackParsers = {
runtime: parseAsStringEnum(
getValidIds("runtime"),
).withDefault(DEFAULT_STACK.runtime),
- backendFramework: parseAsStringEnum(
- getValidIds("backendFramework"),
- ).withDefault(DEFAULT_STACK.backendFramework),
+ backend: parseAsStringEnum(
+ getValidIds("backend"),
+ ).withDefault(DEFAULT_STACK.backend),
api: parseAsStringEnum(getValidIds("api")).withDefault(
DEFAULT_STACK.api,
),
@@ -52,7 +52,7 @@ export const stackUrlKeys: UrlKeys = {
projectName: "name",
frontend: "fe",
runtime: "rt",
- backendFramework: "be",
+ backend: "be",
api: "api",
database: "db",
orm: "orm",
diff --git a/bun.lock b/bun.lock
index 0cc8f3c..7166bd0 100644
--- a/bun.lock
+++ b/bun.lock
@@ -14,7 +14,7 @@
},
"apps/cli": {
"name": "create-better-t-stack",
- "version": "2.2.2",
+ "version": "2.2.4",
"bin": {
"create-better-t-stack": "dist/index.js",
},