add react router

This commit is contained in:
Aman Varshney
2025-04-02 19:50:38 +05:30
parent 6325e647ce
commit dafefb8449
78 changed files with 2160 additions and 748 deletions

View File

@@ -66,7 +66,7 @@ const Navbar = () => {
</span>
</div>
<div className="hidden md:flex justify-center">
<div className="hidden md:block absolute left-1/2 transform -translate-x-1/2">
<div
className={`flex items-center backdrop-blur-sm bg-gray-100/90 dark:bg-gray-900/90 rounded-lg border border-gray-200 dark:border-gray-800 py-1 px-1.5 text-sm relative transition-all duration-500 ease-out ${
scrolled ? "w-[350px]" : "w-[240px]"

View File

@@ -39,13 +39,21 @@ const validateProjectName = (name: string): string | undefined => {
const TECH_OPTIONS = {
frontend: [
{
id: "web",
name: "React Web",
description: "React with TanStack Router",
id: "tanstack-router",
name: "TanStack Router",
description: "Modern type-safe router for React",
icon: "🌐",
color: "from-blue-400 to-blue-600",
default: true,
},
{
id: "react-router",
name: "React Router",
description: "Declarative routing for React",
icon: "🧭",
color: "from-cyan-400 to-cyan-600",
default: false,
},
{
id: "native",
name: "React Native",
@@ -303,7 +311,7 @@ interface StackState {
const DEFAULT_STACK: StackState = {
projectName: "my-better-t-app",
frontend: ["web"],
frontend: ["tanstack-router"],
runtime: "bun",
backendFramework: "hono",
database: "sqlite",
@@ -330,7 +338,10 @@ const StackArchitect = () => {
);
useEffect(() => {
if (!stack.frontend.includes("web") && stack.auth === "true") {
const hasWebFrontend =
stack.frontend.includes("tanstack-router") ||
stack.frontend.includes("react-router");
if (!hasWebFrontend && stack.auth === "true") {
setStack((prev) => ({
...prev,
auth: "false",
@@ -343,16 +354,21 @@ const StackArchitect = () => {
setCommand(cmd);
const notes: Record<string, string[]> = {};
const hasWebFrontend =
stack.frontend.includes("tanstack-router") ||
stack.frontend.includes("react-router");
notes.frontend = [];
notes.auth = [];
if (!stack.frontend.includes("web") && stack.auth === "true") {
notes.auth.push("Authentication is only available with React Web.");
if (!hasWebFrontend && stack.auth === "true") {
notes.auth.push(
"Authentication is only available with React Web (TanStack Router or React Router).",
);
}
notes.addons = [];
if (!stack.frontend.includes("web")) {
if (!hasWebFrontend) {
notes.addons.push("PWA and Tauri are only available with React Web.");
}
@@ -373,7 +389,7 @@ const StackArchitect = () => {
}
notes.examples = [];
if (!stack.frontend.includes("web")) {
if (!hasWebFrontend) {
notes.examples.push(
"Todo and Ai example are only available with React Web.",
);
@@ -398,7 +414,10 @@ const StackArchitect = () => {
if (stackState.frontend.length === 1 && stackState.frontend[0] === "none") {
flags.push("--frontend none");
} else if (
!(stackState.frontend.length === 1 && stackState.frontend[0] === "web")
!(
stackState.frontend.length === 1 &&
stackState.frontend[0] === "tanstack-router"
)
) {
flags.push(`--frontend ${stackState.frontend.join(" ")}`);
}
@@ -455,6 +474,7 @@ const StackArchitect = () => {
setStack((prev) => {
if (category === "frontend") {
const currentSelection = [...prev.frontend];
const webTypes = ["tanstack-router", "react-router"];
if (techId === "none") {
return {
@@ -470,50 +490,81 @@ const StackArchitect = () => {
};
}
if (currentSelection.includes(techId)) {
if (currentSelection.length === 1) {
// Handle web router types (tanstack-router or react-router)
if (webTypes.includes(techId)) {
// If clicking on an already selected web router, do nothing
if (
currentSelection.includes(techId) &&
currentSelection.length === 1
) {
return prev;
}
const newFrontend = currentSelection.filter((id) => id !== techId);
if (techId === "web") {
// If selecting a web router while another one is active, replace it
if (currentSelection.some((id) => webTypes.includes(id))) {
const nonWebSelections = currentSelection.filter(
(id) => !webTypes.includes(id),
);
return {
...prev,
frontend: newFrontend,
auth: "false",
examples: prev.examples.filter(
(ex) => ex !== "todo" && ex !== "ai",
),
addons: prev.addons.filter(
(addon) => addon !== "pwa" && addon !== "tauri",
),
frontend: [...nonWebSelections, techId],
auth: prev.auth, // Keep existing auth setting
};
}
// If no web router was selected before
if (currentSelection.includes("none")) {
return {
...prev,
frontend: [techId],
auth: "true",
};
}
return {
...prev,
frontend: newFrontend,
frontend: [
...currentSelection.filter((id) => id !== "none"),
techId,
],
auth: "true",
};
}
if (currentSelection.includes("none")) {
// Handle native selection
if (techId === "native") {
if (currentSelection.includes(techId)) {
if (currentSelection.length === 1) {
return prev; // Don't allow removing the last frontend
}
return {
...prev,
frontend: currentSelection.filter((id) => id !== techId),
};
}
if (currentSelection.includes("none")) {
return {
...prev,
frontend: [techId],
};
}
return {
...prev,
frontend: [techId],
...(techId === "web" && { auth: "true" }),
frontend: [...currentSelection, techId],
};
}
return {
...prev,
frontend: [...currentSelection, techId],
...(techId === "web" && { auth: "true" }),
};
return prev;
}
if (category === "addons" || category === "examples") {
const currentArray = [...(prev[category] || [])];
const index = currentArray.indexOf(techId);
const hasWebFrontend =
prev.frontend.includes("tanstack-router") ||
prev.frontend.includes("react-router");
if (index >= 0) {
currentArray.splice(index, 1);
@@ -521,14 +572,14 @@ const StackArchitect = () => {
if (
category === "examples" &&
techId === "todo" &&
!prev.frontend.includes("web")
!hasWebFrontend
) {
return prev;
}
if (
category === "addons" &&
(techId === "pwa" || techId === "tauri") &&
!prev.frontend.includes("web")
!hasWebFrontend
) {
return prev;
}
@@ -691,31 +742,32 @@ const StackArchitect = () => {
stack[activeTab as keyof StackState] === tech.id;
}
const hasWebFrontend =
stack.frontend.includes("tanstack-router") ||
stack.frontend.includes("react-router");
const isDisabled =
(activeTab === "orm" && stack.database === "none") ||
(activeTab === "turso" && stack.database !== "sqlite") ||
(activeTab === "auth" && !stack.frontend.includes("web")) ||
(activeTab === "auth" && !hasWebFrontend) ||
(activeTab === "examples" &&
((tech.id === "todo" &&
!stack.frontend.includes("web")) ||
(tech.id === "ai" &&
!stack.frontend.includes("web")))) ||
((tech.id === "todo" && !hasWebFrontend) ||
(tech.id === "ai" && !hasWebFrontend))) ||
(activeTab === "addons" &&
(tech.id === "pwa" || tech.id === "tauri") &&
!stack.frontend.includes("web"));
!hasWebFrontend);
return (
<motion.div
key={tech.id}
className={`
p-2 px-3 rounded
${isDisabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
${
isSelected
? "bg-blue-100 dark:bg-blue-900/40 border border-blue-300 dark:border-blue-500/50"
: "hover:bg-gray-200 dark:hover:bg-gray-800 border border-gray-300 dark:border-gray-700"
}
`}
p-2 px-3 rounded
${isDisabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
${
isSelected
? "bg-blue-100 dark:bg-blue-900/40 border border-blue-300 dark:border-blue-500/50"
: "hover:bg-gray-200 dark:hover:bg-gray-800 border border-gray-300 dark:border-gray-700"
}
`}
whileHover={!isDisabled ? { scale: 1.02 } : undefined}
whileTap={!isDisabled ? { scale: 0.98 } : undefined}
onClick={() =>
@@ -873,13 +925,13 @@ const StackArchitect = () => {
type="button"
key={category}
className={`
py-2 px-4 text-xs font-mono whitespace-nowrap transition-colors
${
activeTab === category
? "bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 border-t-2 border-blue-500"
: "text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-800"
}
`}
py-2 px-4 text-xs font-mono whitespace-nowrap transition-colors
${
activeTab === category
? "bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 border-t-2 border-blue-500"
: "text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-800"
}
`}
onClick={() => setActiveTab(category)}
>
{category}