mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
fix: backend none templates (#241)
This commit is contained in:
5
.changeset/fair-pigs-wash.md
Normal file
5
.changeset/fair-pigs-wash.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"create-better-t-stack": patch
|
||||
---
|
||||
|
||||
fix templates when backend is none
|
||||
@@ -20,9 +20,7 @@ export function displayConfig(config: Partial<ProjectConfig>) {
|
||||
}
|
||||
|
||||
if (config.backend !== undefined) {
|
||||
configDisplay.push(
|
||||
`${pc.blue("Backend Framework:")} ${String(config.backend)}`,
|
||||
);
|
||||
configDisplay.push(`${pc.blue("Backend:")} ${String(config.backend)}`);
|
||||
}
|
||||
|
||||
if (config.runtime !== undefined) {
|
||||
|
||||
@@ -3,40 +3,19 @@ import type { ProjectConfig } from "../types";
|
||||
export function generateReproducibleCommand(config: ProjectConfig): string {
|
||||
const flags: string[] = [];
|
||||
|
||||
if (config.database === "none") {
|
||||
flags.push("--database none");
|
||||
} else {
|
||||
flags.push(`--database ${config.database}`);
|
||||
|
||||
if (config.orm) {
|
||||
flags.push(`--orm ${config.orm}`);
|
||||
}
|
||||
|
||||
if (config.dbSetup) {
|
||||
flags.push(`--db-setup ${config.dbSetup}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.api) {
|
||||
flags.push(`--api ${config.api}`);
|
||||
}
|
||||
|
||||
flags.push(config.auth ? "--auth" : "--no-auth");
|
||||
flags.push(config.git ? "--git" : "--no-git");
|
||||
flags.push(config.install ? "--install" : "--no-install");
|
||||
|
||||
if (config.runtime) {
|
||||
flags.push(`--runtime ${config.runtime}`);
|
||||
}
|
||||
|
||||
if (config.backend) {
|
||||
flags.push(`--backend ${config.backend}`);
|
||||
}
|
||||
|
||||
if (config.frontend && config.frontend.length > 0) {
|
||||
flags.push(`--frontend ${config.frontend.join(" ")}`);
|
||||
} else {
|
||||
flags.push("--frontend none");
|
||||
}
|
||||
|
||||
flags.push(`--backend ${config.backend}`);
|
||||
flags.push(`--runtime ${config.runtime}`);
|
||||
flags.push(`--database ${config.database}`);
|
||||
flags.push(`--orm ${config.orm}`);
|
||||
flags.push(`--api ${config.api}`);
|
||||
flags.push(config.auth ? "--auth" : "--no-auth");
|
||||
|
||||
if (config.addons && config.addons.length > 0) {
|
||||
flags.push(`--addons ${config.addons.join(" ")}`);
|
||||
} else {
|
||||
@@ -49,9 +28,10 @@ export function generateReproducibleCommand(config: ProjectConfig): string {
|
||||
flags.push("--examples none");
|
||||
}
|
||||
|
||||
if (config.packageManager) {
|
||||
flags.push(`--package-manager ${config.packageManager}`);
|
||||
}
|
||||
flags.push(`--db-setup ${config.dbSetup}`);
|
||||
flags.push(config.git ? "--git" : "--no-git");
|
||||
flags.push(`--package-manager ${config.packageManager}`);
|
||||
flags.push(config.install ? "--install" : "--no-install");
|
||||
|
||||
let baseCommand = "";
|
||||
const pkgManager = config.packageManager;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{{#if (includes frontend 'next')}}
|
||||
{{!-- Next.js tRPC Client Setup --}}
|
||||
import { QueryCache, QueryClient } from '@tanstack/react-query';
|
||||
import { createTRPCClient, httpBatchLink } from '@trpc/client';
|
||||
import { createTRPCOptionsProxy } from '@trpc/tanstack-react-query';
|
||||
@@ -47,16 +46,14 @@ export const trpc = createTRPCOptionsProxy<AppRouter>({
|
||||
});
|
||||
|
||||
{{else if (includes frontend 'tanstack-start')}}
|
||||
{{!-- TanStack Start tRPC Client Setup --}}
|
||||
import { createTRPCContext } from "@trpc/tanstack-react-query";
|
||||
import type { AppRouter } from "../../../server/src/routers"; {{! Adjust path if necessary }}
|
||||
import type { AppRouter } from "../../../server/src/routers";
|
||||
|
||||
export const { TRPCProvider, useTRPC, useTRPCClient } =
|
||||
createTRPCContext<AppRouter>();
|
||||
|
||||
{{else}}
|
||||
{{!-- Default Web tRPC Client Setup (TanStack Router, React Router, etc.) --}}
|
||||
import type { AppRouter } from "../../../server/src/routers"; {{! Adjust path if necessary }}
|
||||
import type { AppRouter } from "../../../server/src/routers";
|
||||
import { QueryCache, QueryClient } from "@tanstack/react-query";
|
||||
import { createTRPCClient, httpBatchLink } from "@trpc/client";
|
||||
import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query";
|
||||
|
||||
@@ -12,20 +12,48 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Loader2, Trash2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
{{#if (eq backend "convex")}}
|
||||
import { useMutation, useQuery } from "convex/react";
|
||||
import { api } from "@{{projectName}}/backend/convex/_generated/api.js";
|
||||
import type { Id } from "@{{projectName}}/backend/convex/_generated/dataModel.d.ts";
|
||||
{{else}}
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { trpc } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
|
||||
export default function TodosPage() {
|
||||
const [newTodoText, setNewTodoText] = useState("");
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
{{#if (eq backend "convex")}}
|
||||
const todos = useQuery(api.todos.getAll);
|
||||
const createTodoMutation = useMutation(api.todos.create);
|
||||
const toggleTodoMutation = useMutation(api.todos.toggle);
|
||||
const deleteTodoMutation = useMutation(api.todos.deleteTodo);
|
||||
|
||||
const handleAddTodo = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const text = newTodoText.trim();
|
||||
if (!text) return;
|
||||
await createTodoMutation({ text });
|
||||
setNewTodoText("");
|
||||
};
|
||||
|
||||
const handleToggleTodo = (id: Id<"todos">, currentCompleted: boolean) => {
|
||||
toggleTodoMutation({ id, completed: !currentCompleted });
|
||||
};
|
||||
|
||||
const handleDeleteTodo = (id: Id<"todos">) => {
|
||||
deleteTodoMutation({ id });
|
||||
};
|
||||
{{else}}
|
||||
{{#if (eq api "orpc")}}
|
||||
const todos = useQuery(orpc.todo.getAll.queryOptions());
|
||||
const createMutation = useMutation(
|
||||
orpc.todo.create.mutationOptions({
|
||||
@@ -45,8 +73,8 @@ export default function TodosPage() {
|
||||
onSuccess: () => todos.refetch(),
|
||||
}),
|
||||
);
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
const todos = useQuery(trpc.todo.getAll.queryOptions());
|
||||
const createMutation = useMutation(
|
||||
trpc.todo.create.mutationOptions({
|
||||
@@ -66,7 +94,7 @@ export default function TodosPage() {
|
||||
onSuccess: () => todos.refetch(),
|
||||
}),
|
||||
);
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
const handleAddTodo = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -82,6 +110,7 @@ export default function TodosPage() {
|
||||
const handleDeleteTodo = (id: number) => {
|
||||
deleteMutation.mutate({ id });
|
||||
};
|
||||
{{/if}}
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-md py-10">
|
||||
@@ -99,20 +128,73 @@ export default function TodosPage() {
|
||||
value={newTodoText}
|
||||
onChange={(e) => setNewTodoText(e.target.value)}
|
||||
placeholder="Add a new task..."
|
||||
{{#if (eq backend "convex")}}
|
||||
{{else}}
|
||||
disabled={createMutation.isPending}
|
||||
{{/if}}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
{{#if (eq backend "convex")}}
|
||||
disabled={!newTodoText.trim()}
|
||||
{{else}}
|
||||
disabled={createMutation.isPending || !newTodoText.trim()}
|
||||
{{/if}}
|
||||
>
|
||||
{{#if (eq backend "convex")}}
|
||||
Add
|
||||
{{else}}
|
||||
{createMutation.isPending ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
"Add"
|
||||
)}
|
||||
{{/if}}
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
{{#if (eq backend "convex")}}
|
||||
{todos === undefined ? (
|
||||
<div className="flex justify-center py-4">
|
||||
<Loader2 className="h-6 w-6 animate-spin" />
|
||||
</div>
|
||||
) : todos.length === 0 ? (
|
||||
<p className="py-4 text-center">No todos yet. Add one above!</p>
|
||||
) : (
|
||||
<ul className="space-y-2">
|
||||
{todos.map((todo) => (
|
||||
<li
|
||||
key={todo._id}
|
||||
className="flex items-center justify-between rounded-md border p-2"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={todo.completed}
|
||||
onCheckedChange={() =>
|
||||
handleToggleTodo(todo._id, todo.completed)
|
||||
}
|
||||
id={`todo-${todo._id}`}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`todo-${todo._id}`}
|
||||
className={`${todo.completed ? "line-through text-muted-foreground" : ""}`}
|
||||
>
|
||||
{todo.text}
|
||||
</label>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleDeleteTodo(todo._id)}
|
||||
aria-label="Delete todo"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{{else}}
|
||||
{todos.isLoading ? (
|
||||
<div className="flex justify-center py-4">
|
||||
<Loader2 className="h-6 w-6 animate-spin" />
|
||||
@@ -155,6 +237,7 @@ export default function TodosPage() {
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{{/if}}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -126,7 +126,6 @@ export default function Todos() {
|
||||
onChange={(e) => setNewTodoText(e.target.value)}
|
||||
placeholder="Add a new task..."
|
||||
{{#if (eq backend "convex")}}
|
||||
{{!-- Convex mutations don't have an easy isPending state here, disable based on text --}}
|
||||
{{else}}
|
||||
disabled={createMutation.isPending}
|
||||
{{/if}}
|
||||
|
||||
@@ -33,40 +33,48 @@ export default function Home() {
|
||||
|
||||
<View className="rounded-lg border border-foreground p-4">
|
||||
<Text className="mb-2 font-medium text-foreground">API Status</Text>
|
||||
{{#if (eq backend "convex")}}
|
||||
<View className="flex-row items-center gap-2">
|
||||
<View
|
||||
className={`h-2.5 w-2.5 rounded-full ${
|
||||
{{#if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
healthCheck.data ? "bg-green-500" : "bg-red-500"
|
||||
{{else}}
|
||||
healthCheck ? "bg-green-500" : "bg-red-500"
|
||||
{{/if}}
|
||||
}`}
|
||||
/>
|
||||
<Text className="text-sm text-foreground">
|
||||
{{#if (eq api "orpc")}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
{healthCheck === undefined
|
||||
? "Checking..."
|
||||
: healthCheck === "OK"
|
||||
? "Connected"
|
||||
: "Error"}
|
||||
{{/if}}
|
||||
</Text>
|
||||
</View>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<View className="flex-row items-center gap-2">
|
||||
<View
|
||||
className={`h-2.5 w-2.5 rounded-full ${
|
||||
healthCheck.data ? "bg-green-500" : "bg-red-500"
|
||||
}`}
|
||||
/>
|
||||
<Text className="text-sm text-foreground">
|
||||
{{#if (eq api "orpc")}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
</Text>
|
||||
</View>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</Container>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
{{#if (eq backend "convex")}}
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
import { Stack } from "expo-router";
|
||||
import {
|
||||
@@ -82,6 +84,7 @@ export default function RootLayout() {
|
||||
</ThemeProvider>
|
||||
</ConvexProvider>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
|
||||
<StatusBar style={isDarkColorScheme ? "light" : "dark"} />
|
||||
@@ -96,6 +99,20 @@ export default function RootLayout() {
|
||||
</GestureHandlerRootView>
|
||||
</ThemeProvider>
|
||||
</QueryClientProvider>
|
||||
{{else}}
|
||||
<ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
|
||||
<StatusBar style={isDarkColorScheme ? "light" : "dark"} />
|
||||
<GestureHandlerRootView style=\{{ flex: 1 }}>
|
||||
<Stack>
|
||||
<Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="modal"
|
||||
options=\{{ title: "Modal", presentation: "modal" }}
|
||||
/>
|
||||
</Stack>
|
||||
</GestureHandlerRootView>
|
||||
</ThemeProvider>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,38 +33,54 @@ export default function Home() {
|
||||
|
||||
<View style={styles.apiStatusCard}>
|
||||
<Text style={styles.cardTitle}>API Status</Text>
|
||||
{{#if (eq backend "convex")}}
|
||||
<View style={styles.apiStatusRow}>
|
||||
<View
|
||||
style={[
|
||||
styles.statusIndicatorDot,
|
||||
{{#if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
healthCheck.data
|
||||
? styles.statusIndicatorGreen
|
||||
: styles.statusIndicatorRed,
|
||||
{{else}}
|
||||
healthCheck === "OK"
|
||||
? styles.statusIndicatorGreen
|
||||
: styles.statusIndicatorRed,
|
||||
{{/if}}
|
||||
]}
|
||||
/>
|
||||
<Text style={styles.statusText}>
|
||||
{{#if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
{healthCheck === undefined
|
||||
? "Checking..."
|
||||
: healthCheck === "OK"
|
||||
? "Connected"
|
||||
: "Error"}
|
||||
{{/if}}
|
||||
</Text>
|
||||
</View>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<View style={styles.apiStatusRow}>
|
||||
<View
|
||||
style={[
|
||||
styles.statusIndicatorDot,
|
||||
healthCheck.data
|
||||
? styles.statusIndicatorGreen
|
||||
: styles.statusIndicatorRed,
|
||||
]}
|
||||
/>
|
||||
<Text style={styles.statusText}>
|
||||
{{#if (eq api "orpc")}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
{{/if}}
|
||||
</Text>
|
||||
</View>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</Container>
|
||||
|
||||
@@ -7,7 +7,9 @@ import { queryClient } from "@/utils/orpc";
|
||||
{{#if (eq backend "convex")}}
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
import { Stack } from "expo-router";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
@@ -51,6 +53,7 @@ export default function RootLayout() {
|
||||
</GestureHandlerRootView>
|
||||
</ConvexProvider>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<GestureHandlerRootView style=\{{ flex: 1 }}>
|
||||
<Stack
|
||||
@@ -72,6 +75,27 @@ export default function RootLayout() {
|
||||
</Stack>
|
||||
</GestureHandlerRootView>
|
||||
</QueryClientProvider>
|
||||
{{else}}
|
||||
<GestureHandlerRootView style=\{{ flex: 1 }}>
|
||||
<Stack
|
||||
screenOptions=\{{
|
||||
headerStyle: {
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: theme.colors.typography,
|
||||
},
|
||||
headerTintColor: theme.colors.typography,
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="modal"
|
||||
options=\{{ title: "Modal", presentation: "modal" }}
|
||||
/>
|
||||
</Stack>
|
||||
</GestureHandlerRootView>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
{{#unless (eq api "none")}}
|
||||
const { $orpc } = useNuxtApp()
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
{{/unless}}
|
||||
|
||||
const TITLE_TEXT = `
|
||||
██████╗ ███████╗████████╗████████╗███████╗██████╗
|
||||
@@ -18,14 +20,16 @@ const TITLE_TEXT = `
|
||||
╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
|
||||
`;
|
||||
|
||||
{{#unless (eq api "none")}}
|
||||
const healthCheck = useQuery($orpc.healthCheck.queryOptions())
|
||||
|
||||
{{/unless}}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container mx-auto max-w-3xl px-4 py-2">
|
||||
<pre class="overflow-x-auto font-mono text-sm whitespace-pre-wrap">{{ TITLE_TEXT }}</pre>
|
||||
<div class="grid gap-6 mt-4">
|
||||
{{#unless (eq api "none")}}
|
||||
<section class="rounded-lg border p-4">
|
||||
<h2 class="mb-2 font-medium">API Status</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -58,6 +62,7 @@ const healthCheck = useQuery($orpc.healthCheck.queryOptions())
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -2,14 +2,14 @@
|
||||
{{#if (eq backend "convex")}}
|
||||
import { useQuery } from "convex/react";
|
||||
import { api } from "@{{projectName}}/backend/convex/_generated/api.js";
|
||||
{{else}}
|
||||
{{else if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { trpc } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
{{/if}}
|
||||
|
||||
const TITLE_TEXT = `
|
||||
@@ -43,8 +43,8 @@ export default function Home() {
|
||||
<div className="grid gap-6">
|
||||
<section className="rounded-lg border p-4">
|
||||
<h2 className="mb-2 font-medium">API Status</h2>
|
||||
{{#if (eq backend "convex")}}
|
||||
<div className="flex items-center gap-2">
|
||||
{{#if (eq backend "convex")}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck === "OK" ? "bg-green-500" : healthCheck === undefined ? "bg-orange-400" : "bg-red-500"}`}
|
||||
/>
|
||||
@@ -55,19 +55,23 @@ export default function Home() {
|
||||
? "Connected"
|
||||
: "Error"}
|
||||
</span>
|
||||
{{else}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,49 +1,50 @@
|
||||
"use client"
|
||||
{{#if (eq backend "convex")}}
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
{{else}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc, ORPCContext, queryClient } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { queryClient } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
{{#unless (eq api "none")}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc, ORPCContext, queryClient } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { queryClient } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
import { ThemeProvider } from "./theme-provider";
|
||||
import { Toaster } from "./ui/sonner";
|
||||
|
||||
{{#if (eq backend "convex")}}
|
||||
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
|
||||
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
|
||||
{{/if}}
|
||||
|
||||
export default function Providers({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
{{#if (eq backend "convex")}}
|
||||
<ConvexProvider client={convex}>{children}</ConvexProvider>
|
||||
{{else}}
|
||||
export default function Providers({ children, }: { children: React.ReactNode })
|
||||
{ return (
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
{{#if (eq backend "convex")}}
|
||||
<ConvexProvider client={convex}>{children}</ConvexProvider>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{{#if (eq api "orpc")}}
|
||||
<ORPCContext.Provider value={orpc}>
|
||||
{children}
|
||||
</ORPCContext.Provider>
|
||||
<ORPCContext.Provider value={orpc}>
|
||||
{children}
|
||||
</ORPCContext.Provider>
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{children}
|
||||
{children}
|
||||
{{/if}}
|
||||
</QueryClientProvider>
|
||||
{{/if}}
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
{{else}}
|
||||
{children}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
) }
|
||||
|
||||
@@ -13,20 +13,25 @@ import { ThemeProvider } from "./components/theme-provider";
|
||||
import { Toaster } from "./components/ui/sonner";
|
||||
|
||||
{{#if (eq backend "convex")}}
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
{{else}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc, ORPCContext, queryClient } from "./utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { queryClient } from "./utils/trpc";
|
||||
{{/if}}
|
||||
{{#unless (eq api "none")}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc, ORPCContext, queryClient } from "./utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { queryClient } from "./utils/trpc";
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
export const links: Route.LinksFunction = () => [
|
||||
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
|
||||
{
|
||||
rel: "preconnect",
|
||||
href: "https://fonts.googleapis.com",
|
||||
},
|
||||
{
|
||||
rel: "preconnect",
|
||||
href: "https://fonts.gstatic.com",
|
||||
@@ -57,28 +62,12 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
|
||||
{{#if (eq backend "convex")}}
|
||||
export default function App() {
|
||||
const convex = new ConvexReactClient(
|
||||
import.meta.env.VITE_CONVEX_URL as string,
|
||||
);
|
||||
|
||||
return (
|
||||
<ConvexProvider client={convex}>
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
<Outlet />
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
</ConvexProvider>
|
||||
);
|
||||
}
|
||||
{{else if (eq api "orpc")}}
|
||||
export default function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ORPCContext.Provider value={orpc}>
|
||||
export default function App() {
|
||||
const convex = new ConvexReactClient(
|
||||
import.meta.env.VITE_CONVEX_URL as string,
|
||||
);
|
||||
return (
|
||||
<ConvexProvider client={convex}>
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
@@ -86,15 +75,44 @@ export default function App() {
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
</ORPCContext.Provider>
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
</ConvexProvider>
|
||||
);
|
||||
}
|
||||
{{else if (eq api "orpc")}}
|
||||
export default function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ORPCContext.Provider value={orpc}>
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
<Outlet />
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
</ORPCContext.Provider>
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
{{else if (eq api "trpc")}}
|
||||
export default function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
export default function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
<Outlet />
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
{{else}}
|
||||
export default function App() {
|
||||
return (
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
@@ -102,10 +120,8 @@ export default function App() {
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
{{/if}}
|
||||
|
||||
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
||||
|
||||
@@ -2,14 +2,14 @@ import type { Route } from "./+types/_index";
|
||||
{{#if (eq backend "convex")}}
|
||||
import { useQuery } from "convex/react";
|
||||
import { api } from "@{{projectName}}/backend/convex/_generated/api.js";
|
||||
{{else}}
|
||||
{{else if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { trpc } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
{{/if}}
|
||||
|
||||
const TITLE_TEXT = `
|
||||
@@ -47,8 +47,8 @@ export default function Home() {
|
||||
<div className="grid gap-6">
|
||||
<section className="rounded-lg border p-4">
|
||||
<h2 className="mb-2 font-medium">API Status</h2>
|
||||
{{#if (eq backend "convex")}}
|
||||
<div className="flex items-center gap-2">
|
||||
{{#if (eq backend "convex")}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck === "OK" ? "bg-green-500" : healthCheck === undefined ? "bg-orange-400" : "bg-red-500"}`}
|
||||
/>
|
||||
@@ -59,21 +59,25 @@ export default function Home() {
|
||||
? "Connected"
|
||||
: "Error"}
|
||||
</span>
|
||||
{{else}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${
|
||||
healthCheck.data ? "bg-green-500" : "bg-red-500"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${
|
||||
healthCheck.data ? "bg-green-500" : "bg-red-500"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,57 +2,51 @@ import { RouterProvider, createRouter } from "@tanstack/react-router";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import Loader from "./components/loader";
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { orpc, queryClient } from "./utils/orpc";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { orpc, queryClient } from "./utils/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { queryClient, trpc } from "./utils/trpc";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { queryClient, trpc } from "./utils/trpc";
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
|
||||
const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string);
|
||||
import { ConvexProvider, ConvexReactClient } from "convex/react";
|
||||
const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string);
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
defaultPreload: "intent",
|
||||
defaultPendingComponent: () => <Loader />,
|
||||
{{#if (eq api "orpc")}}
|
||||
context: { orpc, queryClient },
|
||||
Wrap: function WrapComponent({ children }) {
|
||||
Wrap: function WrapComponent({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
);
|
||||
},
|
||||
});
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
defaultPreload: "intent",
|
||||
defaultPendingComponent: () => <Loader />,
|
||||
{{else if (eq api "trpc")}}
|
||||
context: { trpc, queryClient },
|
||||
Wrap: function WrapComponent({ children }) {
|
||||
Wrap: function WrapComponent({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
);
|
||||
},
|
||||
});
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
defaultPreload: "intent",
|
||||
defaultPendingComponent: () => <Loader />,
|
||||
{{else if (eq backend "convex")}}
|
||||
context: {},
|
||||
Wrap: function WrapComponent({ children }) {
|
||||
Wrap: function WrapComponent({ children }: { children: React.ReactNode }) {
|
||||
return <ConvexProvider client={convex}>{children}</ConvexProvider>;
|
||||
},
|
||||
{{else}}
|
||||
context: {},
|
||||
{{/if}}
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
declare module "@tanstack/react-router" {
|
||||
interface Register {
|
||||
@@ -61,7 +55,10 @@ declare module "@tanstack/react-router" {
|
||||
}
|
||||
|
||||
const rootElement = document.getElementById("app");
|
||||
if (!rootElement) throw new Error("Root element not found");
|
||||
|
||||
if (!rootElement) {
|
||||
throw new Error("Root element not found");
|
||||
}
|
||||
|
||||
if (!rootElement.innerHTML) {
|
||||
const root = ReactDOM.createRoot(rootElement);
|
||||
|
||||
@@ -31,14 +31,12 @@ export interface RouterAppContext {
|
||||
orpc: typeof orpc;
|
||||
queryClient: QueryClient;
|
||||
}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{{else if (eq api "trpc")}}
|
||||
export interface RouterAppContext {
|
||||
trpc: typeof trpc;
|
||||
queryClient: QueryClient;
|
||||
}
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
{{else}}
|
||||
export interface RouterAppContext {}
|
||||
{{/if}}
|
||||
|
||||
@@ -63,18 +61,21 @@ export const Route = createRootRouteWithContext<RouterAppContext>()({
|
||||
}),
|
||||
});
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
function RootComponent() {
|
||||
const [client] = useState<RouterClient<typeof appRouter>>(() => createORPCClient(link))
|
||||
const [orpc] = useState(() => createORPCReactQueryUtils(client))
|
||||
|
||||
const isFetching = useRouterState({
|
||||
select: (s) => s.isLoading,
|
||||
});
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
const [client] = useState<RouterClient<typeof appRouter>>(() => createORPCClient(link));
|
||||
const [orpcUtils] = useState(() => createORPCReactQueryUtils(client));
|
||||
{{/if}}
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeadContent />
|
||||
<ORPCContext.Provider value={orpc}>
|
||||
{{#if (eq api "orpc")}}
|
||||
<ORPCContext.Provider value={orpcUtils}>
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
@@ -83,20 +84,7 @@ function RootComponent() {
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
</ORPCContext.Provider>
|
||||
<TanStackRouterDevtools position="bottom-left" />
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
function RootComponent() {
|
||||
const isFetching = useRouterState({
|
||||
select: (s) => s.isLoading,
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<HeadContent />
|
||||
{{else}}
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
@@ -104,29 +92,11 @@ function RootComponent() {
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
{{/if}}
|
||||
<TanStackRouterDevtools position="bottom-left" />
|
||||
{{#if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
{{/if}}
|
||||
</>
|
||||
);
|
||||
}
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
function RootComponent() {
|
||||
const isFetching = useRouterState({
|
||||
select: (s) => s.isLoading,
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<HeadContent />
|
||||
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
|
||||
<div className="grid grid-rows-[auto_1fr] h-svh">
|
||||
<Header />
|
||||
{isFetching ? <Loader /> : <Outlet />}
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</ThemeProvider>
|
||||
<TanStackRouterDevtools position="bottom-left" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
{{/if}}
|
||||
|
||||
@@ -49,20 +49,8 @@ function HomeComponent() {
|
||||
<div className="grid gap-6">
|
||||
<section className="rounded-lg border p-4">
|
||||
<h2 className="mb-2 font-medium">API Status</h2>
|
||||
{{#if (eq backend "convex")}}
|
||||
<div className="flex items-center gap-2">
|
||||
{{#if (or (eq api "orpc") (eq api "trpc"))}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{#if (eq backend "convex")}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck === "OK" ? "bg-green-500" : healthCheck === undefined ? "bg-orange-400" : "bg-red-500"}`}
|
||||
/>
|
||||
@@ -73,8 +61,23 @@ function HomeComponent() {
|
||||
? "Connected"
|
||||
: "Error"}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
/>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,24 +8,20 @@ import { routeTree } from "./routeTree.gen";
|
||||
import Loader from "./components/loader";
|
||||
import "./index.css";
|
||||
{{else}}
|
||||
import {
|
||||
QueryCache,
|
||||
QueryClient,
|
||||
QueryClientProvider,
|
||||
} from "@tanstack/react-query";
|
||||
import { createRouter as createTanstackRouter } from "@tanstack/react-router";
|
||||
import Loader from "./components/loader";
|
||||
import "./index.css";
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
{{#if (eq api "trpc")}}
|
||||
import { QueryCache, QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { createTRPCClient, httpBatchLink } from "@trpc/client";
|
||||
import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query";
|
||||
import { toast } from "sonner";
|
||||
import type { AppRouter } from "../../server/src/routers";
|
||||
import { TRPCProvider } from "./utils/trpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc, ORPCContext, queryClient } from "./utils/orpc";
|
||||
{{else if (eq api "orpc")}}
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { orpc, ORPCContext, queryClient as orpcQueryClient } from "./utils/orpc";
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -62,7 +58,6 @@ export function createRouter() {
|
||||
}),
|
||||
queryClient,
|
||||
);
|
||||
|
||||
return router;
|
||||
}
|
||||
{{else}}
|
||||
@@ -103,6 +98,8 @@ const trpc = createTRPCOptionsProxy({
|
||||
client: trpcClient,
|
||||
queryClient: queryClient,
|
||||
});
|
||||
{{else if (eq api "orpc")}}
|
||||
const queryClient = orpcQueryClient;
|
||||
{{/if}}
|
||||
|
||||
export const createRouter = () => {
|
||||
@@ -112,33 +109,37 @@ export const createRouter = () => {
|
||||
defaultPreloadStaleTime: 0,
|
||||
{{#if (eq api "trpc")}}
|
||||
context: { trpc, queryClient },
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
{{else if (eq api "orpc")}}
|
||||
context: { orpc, queryClient },
|
||||
{{else}}
|
||||
context: { },
|
||||
{{/if}}
|
||||
defaultPendingComponent: () => <Loader />,
|
||||
defaultNotFoundComponent: () => <div>Not Found</div>,
|
||||
{{#if (eq api "trpc")}}
|
||||
Wrap: ({ children }) => (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{{#if (eq api "trpc")}}
|
||||
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
|
||||
{children}
|
||||
</TRPCProvider>
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
</QueryClientProvider>
|
||||
),
|
||||
{{else if (eq api "orpc")}}
|
||||
Wrap: ({ children }) => (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ORPCContext.Provider value={orpc}>
|
||||
{children}
|
||||
</ORPCContext.Provider>
|
||||
{{/if}}
|
||||
</QueryClientProvider>
|
||||
),
|
||||
{{else}}
|
||||
Wrap: ({ children }) => <>{children}</>,
|
||||
{{/if}}
|
||||
});
|
||||
|
||||
return router;
|
||||
};
|
||||
{{/if}}
|
||||
|
||||
// Register the router instance for type safety
|
||||
declare module "@tanstack/react-router" {
|
||||
interface Register {
|
||||
router: ReturnType<typeof createRouter>;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
{{#unless (eq backend "convex")}} {{#unless (eq api "none")}}
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
{{/unless}} {{/unless}}
|
||||
import {
|
||||
HeadContent,
|
||||
Outlet,
|
||||
@@ -10,7 +12,9 @@ import {
|
||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
||||
import Header from "../components/header";
|
||||
import appCss from "../index.css?url";
|
||||
{{#unless (and (eq api "none") (not (eq backend "convex"))}}
|
||||
import type { QueryClient } from "@tanstack/react-query";
|
||||
{{/unless}}
|
||||
import Loader from "@/components/loader";
|
||||
|
||||
{{#if (eq backend "convex")}}
|
||||
@@ -25,12 +29,14 @@ export interface RouterAppContext {
|
||||
trpc: TRPCOptionsProxy<AppRouter>;
|
||||
queryClient: QueryClient;
|
||||
}
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
{{else if (eq api "orpc")}}
|
||||
import type { orpc } from "@/utils/orpc";
|
||||
export interface RouterAppContext {
|
||||
orpc: typeof orpc;
|
||||
queryClient: QueryClient;
|
||||
}
|
||||
{{else}}
|
||||
export interface RouterAppContext {
|
||||
}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
@@ -75,7 +81,11 @@ function RootDocument() {
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
<TanStackRouterDevtools position="bottom-left" />
|
||||
{{#unless (eq backend "convex")}}
|
||||
{{#unless (eq api "none")}}
|
||||
<ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
|
||||
{{/unless}}
|
||||
{{/unless}}
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,14 +3,14 @@ import { createFileRoute } from "@tanstack/react-router";
|
||||
import { convexQuery } from "@convex-dev/react-query";
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { api } from "@{{projectName}}/backend/convex/_generated/api.js";
|
||||
{{else}}
|
||||
{{else if (or (eq api "trpc") (eq api "orpc"))}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
{{#if (eq api "trpc")}}
|
||||
import { useTRPC } from "@/utils/trpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
import { useORPC } from "@/utils/orpc";
|
||||
{{/if}}
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
{{/if}}
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
@@ -36,15 +36,12 @@ const TITLE_TEXT = `
|
||||
function HomeComponent() {
|
||||
{{#if (eq backend "convex")}}
|
||||
const healthCheck = useSuspenseQuery(convexQuery(api.healthCheck.get, {}));
|
||||
{{else}}
|
||||
{{#if (eq api "trpc")}}
|
||||
{{else if (eq api "trpc")}}
|
||||
const trpc = useTRPC();
|
||||
const healthCheck = useQuery(trpc.healthCheck.queryOptions());
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
{{else if (eq api "orpc")}}
|
||||
const orpc = useORPC();
|
||||
const healthCheck = useQuery(orpc.healthCheck.queryOptions());
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
return (
|
||||
@@ -53,8 +50,8 @@ function HomeComponent() {
|
||||
<div className="grid gap-6">
|
||||
<section className="rounded-lg border p-4">
|
||||
<h2 className="mb-2 font-medium">API Status</h2>
|
||||
{{#if (eq backend "convex")}}
|
||||
<div className="flex items-center gap-2">
|
||||
{{#if (eq backend "convex")}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck.data === "OK" ? "bg-green-500" : healthCheck.isLoading ? "bg-orange-400" : "bg-red-500"}`}
|
||||
/>
|
||||
@@ -65,19 +62,23 @@ function HomeComponent() {
|
||||
? "Connected"
|
||||
: "Error"}
|
||||
</span>
|
||||
{{else}}
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
/>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{#unless (eq api "none")}}
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
/>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{healthCheck.isLoading
|
||||
? "Checking..."
|
||||
: healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,10 @@ import { RouterProvider, createRouter } from "@tanstack/solid-router";
|
||||
import { render } from "solid-js/web";
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
import "./styles.css";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { QueryClientProvider } from "@tanstack/solid-query";
|
||||
import { queryClient } from "./utils/orpc";
|
||||
{{/if}}
|
||||
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
@@ -20,9 +22,13 @@ declare module "@tanstack/solid-router" {
|
||||
|
||||
function App() {
|
||||
return (
|
||||
{{#if (eq api "orpc")}}
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{{/if}}
|
||||
<RouterProvider router={router} />
|
||||
{{#if (eq api "orpc")}}
|
||||
</QueryClientProvider>
|
||||
{{/if}}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import Header from "@/components/header";
|
||||
import { Outlet, createRootRouteWithContext } from "@tanstack/solid-router";
|
||||
import { TanStackRouterDevtools } from "@tanstack/solid-router-devtools";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { SolidQueryDevtools } from "@tanstack/solid-query-devtools";
|
||||
import type { QueryClient } from "@tanstack/solid-query";
|
||||
import type { orpc } from "../utils/orpc";
|
||||
|
||||
export const Route = createRootRouteWithContext()({
|
||||
export interface RouterContext {
|
||||
orpc: typeof orpc;
|
||||
queryClient: QueryClient;
|
||||
}
|
||||
{{else}}
|
||||
export interface RouterContext {}
|
||||
{{/if}}
|
||||
|
||||
export const Route = createRootRouteWithContext<RouterContext>()({
|
||||
component: RootComponent,
|
||||
});
|
||||
|
||||
@@ -14,7 +25,9 @@ function RootComponent() {
|
||||
<Header />
|
||||
<Outlet />
|
||||
</div>
|
||||
{{#if (eq api "orpc")}}
|
||||
<SolidQueryDevtools />
|
||||
{{/if}}
|
||||
<TanStackRouterDevtools />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { createFileRoute } from "@tanstack/solid-router";
|
||||
{{#if (eq api "orpc")}}
|
||||
import { useQuery } from "@tanstack/solid-query";
|
||||
import { orpc } from "../utils/orpc";
|
||||
import { Match, Switch } from "solid-js";
|
||||
{{else}}
|
||||
{{/if}}
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: App,
|
||||
@@ -24,12 +27,15 @@ const TITLE_TEXT = `
|
||||
`;
|
||||
|
||||
function App() {
|
||||
{{#if (eq api "orpc")}}
|
||||
const healthCheck = useQuery(() => orpc.healthCheck.queryOptions());
|
||||
{{/if}}
|
||||
|
||||
return (
|
||||
<div class="container mx-auto max-w-3xl px-4 py-2">
|
||||
<pre class="overflow-x-auto font-mono text-sm">{TITLE_TEXT}</pre>
|
||||
<div class="grid gap-6">
|
||||
{{#if (eq api "orpc")}}
|
||||
<section class="rounded-lg border p-4">
|
||||
<h2 class="mb-2 font-medium">API Status</h2>
|
||||
<Switch>
|
||||
@@ -53,12 +59,13 @@ function App() {
|
||||
<span class="text-sm text-muted-foreground">
|
||||
{healthCheck.data
|
||||
? "Connected"
|
||||
: "Disconnected (Success but no data)"}
|
||||
: "Disconnected"}
|
||||
</span>
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
</section>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,16 +16,12 @@
|
||||
</main>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if (eq api "orpc")}}
|
||||
<script lang="ts">
|
||||
import { QueryClientProvider } from '@tanstack/svelte-query';
|
||||
import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
|
||||
import '../app.css';
|
||||
{{#if (eq api "orpc")}}
|
||||
import { queryClient } from '$lib/orpc';
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { queryClient } from '$lib/trpc';
|
||||
{{/if}}
|
||||
import Header from '../components/Header.svelte';
|
||||
|
||||
let { children } = $props();
|
||||
@@ -40,4 +36,19 @@
|
||||
</div>
|
||||
<SvelteQueryDevtools />
|
||||
</QueryClientProvider>
|
||||
{{else}}
|
||||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import Header from '../components/Header.svelte';
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<div class="grid h-svh grid-rows-[auto_1fr]">
|
||||
<Header />
|
||||
<main class="overflow-y-auto">
|
||||
{@render children()}
|
||||
</main>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
import { useQuery } from 'convex-svelte';
|
||||
import { api } from "@{{projectName}}/backend/convex/_generated/api.js";
|
||||
|
||||
|
||||
const healthCheck = useQuery(api.healthCheck.get, {});
|
||||
|
||||
|
||||
const TITLE_TEXT = `
|
||||
██████╗ ███████╗████████╗████████╗███████╗██████╗
|
||||
██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗
|
||||
@@ -28,7 +26,7 @@ const TITLE_TEXT = `
|
||||
<pre class="overflow-x-auto font-mono text-sm">{TITLE_TEXT}</pre>
|
||||
<div class="grid gap-6">
|
||||
<section class="rounded-lg border p-4">
|
||||
<h2 class="mb-2 font-medium">API Status (Convex)</h2>
|
||||
<h2 class="mb-2 font-medium">API Status</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
@@ -48,19 +46,9 @@ const TITLE_TEXT = `
|
||||
<script lang="ts">
|
||||
{{#if (eq api "orpc")}}
|
||||
import { orpc } from "$lib/orpc";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { trpc } from "$lib/trpc";
|
||||
{{/if}}
|
||||
import { createQuery } from "@tanstack/svelte-query";
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
const healthCheck = createQuery(orpc.healthCheck.queryOptions());
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
const healthCheck = createQuery(trpc.healthCheck.queryOptions());
|
||||
{{/if}}
|
||||
|
||||
|
||||
const TITLE_TEXT = `
|
||||
██████╗ ███████╗████████╗████████╗███████╗██████╗
|
||||
@@ -82,8 +70,9 @@ const TITLE_TEXT = `
|
||||
<div class="container mx-auto max-w-3xl px-4 py-2">
|
||||
<pre class="overflow-x-auto font-mono text-sm">{TITLE_TEXT}</pre>
|
||||
<div class="grid gap-6">
|
||||
{{#if (eq api "orpc")}}
|
||||
<section class="rounded-lg border p-4">
|
||||
<h2 class="mb-2 font-medium">API Status{{#if (eq api "trpc")}} (tRPC){{/if}}{{#if (eq api "orpc")}} (oRPC){{/if}}</h2>
|
||||
<h2 class="mb-2 font-medium">API Status</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class={`h-2 w-2 rounded-full ${$healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
|
||||
@@ -97,6 +86,7 @@ const TITLE_TEXT = `
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
22
bun.lock
22
bun.lock
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"apps/cli": {
|
||||
"name": "create-better-t-stack",
|
||||
"version": "2.9.0",
|
||||
"version": "2.9.2",
|
||||
"bin": {
|
||||
"create-better-t-stack": "dist/index.js",
|
||||
},
|
||||
@@ -43,9 +43,9 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "^1.1.13",
|
||||
"@radix-ui/react-scroll-area": "^1.2.6",
|
||||
"@radix-ui/react-switch": "^1.2.2",
|
||||
"@radix-ui/react-tooltip": "^1.2.4",
|
||||
"@radix-ui/react-scroll-area": "^1.2.8",
|
||||
"@radix-ui/react-switch": "^1.2.4",
|
||||
"@radix-ui/react-tooltip": "^1.2.6",
|
||||
"babel-plugin-react-compiler": "^19.1.0-rc.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -53,7 +53,7 @@
|
||||
"fumadocs-mdx": "11.6.1",
|
||||
"fumadocs-ui": "15.2.10",
|
||||
"lucide-react": "^0.503.0",
|
||||
"motion": "^12.8.0",
|
||||
"motion": "^12.10.5",
|
||||
"next": "15.3.1",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.4.3",
|
||||
@@ -64,16 +64,16 @@
|
||||
"tailwind-merge": "^3.2.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.4",
|
||||
"@tailwindcss/postcss": "^4.1.5",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "22.14.1",
|
||||
"@types/react": "^19.1.2",
|
||||
"@types/react-dom": "^19.1.2",
|
||||
"eslint": "^9.25.1",
|
||||
"@types/react": "^19.1.3",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-next": "15.3.1",
|
||||
"postcss": "^8.5.3",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"tw-animate-css": "^1.2.8",
|
||||
"tailwindcss": "^4.1.5",
|
||||
"tw-animate-css": "^1.2.9",
|
||||
"typescript": "^5.8.3",
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user