mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
Add frontend selection options and improve CLI command generation
This commit is contained in:
@@ -69,6 +69,32 @@ const triggerConfetti = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const TECH_OPTIONS = {
|
const TECH_OPTIONS = {
|
||||||
|
frontend: [
|
||||||
|
{
|
||||||
|
id: "web",
|
||||||
|
name: "React Web",
|
||||||
|
description: "React with TanStack Router",
|
||||||
|
icon: "🌐",
|
||||||
|
color: "from-blue-400 to-blue-600",
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "native",
|
||||||
|
name: "React Native",
|
||||||
|
description: "Expo with NativeWind",
|
||||||
|
icon: "📱",
|
||||||
|
color: "from-purple-400 to-purple-600",
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "none",
|
||||||
|
name: "No Frontend",
|
||||||
|
description: "API-only backend",
|
||||||
|
icon: "⚙️",
|
||||||
|
color: "from-gray-400 to-gray-600",
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
runtime: [
|
runtime: [
|
||||||
{
|
{
|
||||||
id: "bun",
|
id: "bun",
|
||||||
@@ -284,6 +310,7 @@ const TECH_OPTIONS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface StackState {
|
interface StackState {
|
||||||
|
frontend: string[];
|
||||||
runtime: string;
|
runtime: string;
|
||||||
backendFramework: string;
|
backendFramework: string;
|
||||||
database: string;
|
database: string;
|
||||||
@@ -298,6 +325,7 @@ interface StackState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_STACK: StackState = {
|
const DEFAULT_STACK: StackState = {
|
||||||
|
frontend: ["web"],
|
||||||
runtime: "bun",
|
runtime: "bun",
|
||||||
backendFramework: "hono",
|
backendFramework: "hono",
|
||||||
database: "sqlite",
|
database: "sqlite",
|
||||||
@@ -323,11 +351,21 @@ const StackArchitect = () => {
|
|||||||
}, [stack]);
|
}, [stack]);
|
||||||
|
|
||||||
const generateCommand = useCallback((stackState: StackState) => {
|
const generateCommand = useCallback((stackState: StackState) => {
|
||||||
const base = "npx create-better-t-stack";
|
let base: string;
|
||||||
const projectName = "my-better-t-app";
|
if (stackState.packageManager === "npm") {
|
||||||
const flags: string[] = ["-y"];
|
base = "npx create-better-t-stack@latest";
|
||||||
|
} else if (stackState.packageManager === "pnpm") {
|
||||||
|
base = "pnpm create better-t-stack@latest";
|
||||||
|
} else {
|
||||||
|
base = "bun create better-t-stack@latest";
|
||||||
|
}
|
||||||
|
|
||||||
const isDefault =
|
const projectName = "my-better-t-app";
|
||||||
|
const flags: string[] = [];
|
||||||
|
|
||||||
|
const isAllDefault =
|
||||||
|
stackState.frontend.length === 1 &&
|
||||||
|
stackState.frontend[0] === "web" &&
|
||||||
stackState.runtime === "bun" &&
|
stackState.runtime === "bun" &&
|
||||||
stackState.backendFramework === "hono" &&
|
stackState.backendFramework === "hono" &&
|
||||||
stackState.database === "sqlite" &&
|
stackState.database === "sqlite" &&
|
||||||
@@ -340,14 +378,26 @@ const StackArchitect = () => {
|
|||||||
stackState.git === "true" &&
|
stackState.git === "true" &&
|
||||||
stackState.install === "true";
|
stackState.install === "true";
|
||||||
|
|
||||||
if (isDefault) return `${base} ${projectName} -y`;
|
if (isAllDefault) {
|
||||||
|
return `${base} ${projectName} -y`;
|
||||||
if (stackState.runtime === "node") {
|
|
||||||
flags.push("--runtime node");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackState.backendFramework === "elysia") {
|
flags.push("-y");
|
||||||
flags.push("--elysia");
|
|
||||||
|
if (!stackState.frontend.includes("web")) {
|
||||||
|
flags.push("--no-web");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stackState.frontend.includes("native")) {
|
||||||
|
flags.push("--native");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stackState.runtime !== "bun") {
|
||||||
|
flags.push(`--runtime ${stackState.runtime}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stackState.backendFramework !== "hono") {
|
||||||
|
flags.push(`--${stackState.backendFramework}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackState.database === "postgres") {
|
if (stackState.database === "postgres") {
|
||||||
@@ -356,7 +406,7 @@ const StackArchitect = () => {
|
|||||||
flags.push("--no-database");
|
flags.push("--no-database");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackState.orm === "prisma") {
|
if (stackState.orm === "prisma" && stackState.database !== "none") {
|
||||||
flags.push("--prisma");
|
flags.push("--prisma");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +414,7 @@ const StackArchitect = () => {
|
|||||||
flags.push("--no-auth");
|
flags.push("--no-auth");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackState.turso === "true") {
|
if (stackState.turso === "true" && stackState.database === "sqlite") {
|
||||||
flags.push("--turso");
|
flags.push("--turso");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,14 +440,35 @@ const StackArchitect = () => {
|
|||||||
flags.push("--no-install");
|
flags.push("--no-install");
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags.length > 0
|
return `${base} ${projectName} ${flags.join(" ")}`;
|
||||||
? `${base} ${projectName} ${flags.join(" ")}`
|
|
||||||
: `${base} ${projectName}`;
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleTechSelect = useCallback(
|
const handleTechSelect = useCallback(
|
||||||
(category: keyof typeof TECH_OPTIONS, techId: string) => {
|
(category: keyof typeof TECH_OPTIONS, techId: string) => {
|
||||||
setStack((prev) => {
|
setStack((prev) => {
|
||||||
|
if (category === "frontend") {
|
||||||
|
const currentSelection = [...prev.frontend];
|
||||||
|
|
||||||
|
if (techId === "none") {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
frontend: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSelection.includes(techId)) {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
frontend: currentSelection.filter((id) => id !== techId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
frontend: [...currentSelection, techId],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (category === "addons" || category === "examples") {
|
if (category === "addons" || category === "examples") {
|
||||||
const currentArray = [...(prev[category] || [])];
|
const currentArray = [...(prev[category] || [])];
|
||||||
const index = currentArray.indexOf(techId);
|
const index = currentArray.indexOf(techId);
|
||||||
@@ -518,6 +589,8 @@ const StackArchitect = () => {
|
|||||||
let isSelected = false;
|
let isSelected = false;
|
||||||
if (activeTab === "addons" || activeTab === "examples") {
|
if (activeTab === "addons" || activeTab === "examples") {
|
||||||
isSelected = stack[activeTab].includes(tech.id);
|
isSelected = stack[activeTab].includes(tech.id);
|
||||||
|
} else if (activeTab === "frontend") {
|
||||||
|
isSelected = stack.frontend.includes(tech.id);
|
||||||
} else {
|
} else {
|
||||||
isSelected =
|
isSelected =
|
||||||
stack[activeTab as keyof StackState] === tech.id;
|
stack[activeTab as keyof StackState] === tech.id;
|
||||||
@@ -591,6 +664,19 @@ const StackArchitect = () => {
|
|||||||
Selected Stack
|
Selected Stack
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{stack.frontend.map((frontendId) => {
|
||||||
|
const frontend = TECH_OPTIONS.frontend.find(
|
||||||
|
(f) => f.id === frontendId,
|
||||||
|
);
|
||||||
|
return frontend ? (
|
||||||
|
<span
|
||||||
|
key={frontendId}
|
||||||
|
className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300 border border-blue-300 dark:border-blue-700/30"
|
||||||
|
>
|
||||||
|
{frontend.icon} {frontend.name}
|
||||||
|
</span>
|
||||||
|
) : null;
|
||||||
|
})}
|
||||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300 border border-amber-300 dark:border-amber-700/30">
|
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300 border border-amber-300 dark:border-amber-700/30">
|
||||||
{
|
{
|
||||||
TECH_OPTIONS.runtime.find((t) => t.id === stack.runtime)
|
TECH_OPTIONS.runtime.find((t) => t.id === stack.runtime)
|
||||||
|
|||||||
Reference in New Issue
Block a user