Working React Router Option; Update Github Action for reactrouter option 4e48f917
Maximilian Leodolter · 2025-08-07 14:37 10 file(s) · +790 −13
.github/workflows/test-cli-options.yml +163 −13
2 2
3 3
on:
4 4
  push:
5 -
    branches: [ main ]
5 +
    branches: [main]
6 6
  pull_request:
7 -
    branches: [ main ]
7 +
    branches: [main]
8 8
9 9
jobs:
10 10
  test-cli-options:
11 11
    runs-on: ubuntu-latest
12 -
    
12 +
13 13
    strategy:
14 14
      fail-fast: false
15 15
      matrix:
63 63
            router: "none"
64 64
            linter: "biome"
65 65
            test_name: "Default + No RPC + TanStack Query + Biome"
66 -
          
66 +
67 67
          # Tailwind template combinations
68 68
          - template: "tailwind"
69 69
            rpc: true
131 131
            rpc: false
132 132
            tanstackQuery: false
133 133
            router: "none"
134 -
            router: "none"
135 134
            linter: "eslint"
136 135
            test_name: "Shadcn + No RPC + No TanStack Query + ESLint"
137 136
          - template: "shadcn"
161 160
          - template: "shadcn"
162 161
            rpc: false
163 162
            tanstackQuery: true
164 -
            router: "none"
163 +
            router: "reactrouter"
164 +
            linter: "biome"
165 +
            test_name: "Shadcn + No RPC + TanStack Query + Biome"
166 +
167 +
          # React Router
168 +
          # Default template combinations
169 +
          - template: "default"
170 +
            rpc: true
171 +
            tanstackQuery: false
172 +
            router: "reactrouter"
173 +
            linter: "eslint"
174 +
            test_name: "Default + RPC + No TanStack Query + ESLint"
175 +
          - template: "default"
176 +
            rpc: true
177 +
            tanstackQuery: false
178 +
            router: "reactrouter"
179 +
            linter: "biome"
180 +
            test_name: "Default + RPC + No TanStack Query + Biome"
181 +
          - template: "default"
182 +
            rpc: false
183 +
            tanstackQuery: false
184 +
            router: "reactrouter"
185 +
            linter: "eslint"
186 +
            test_name: "Default + No RPC + No TanStack Query + ESLint"
187 +
          - template: "default"
188 +
            rpc: false
189 +
            tanstackQuery: false
190 +
            router: "reactrouter"
191 +
            linter: "biome"
192 +
            test_name: "Default + No RPC + No TanStack Query + Biome"
193 +
          - template: "default"
194 +
            rpc: true
195 +
            tanstackQuery: true
196 +
            router: "reactrouter"
197 +
            linter: "eslint"
198 +
            test_name: "Default + RPC + TanStack Query + ESLint"
199 +
          - template: "default"
200 +
            rpc: true
201 +
            tanstackQuery: true
202 +
            router: "reactrouter"
203 +
            linter: "biome"
204 +
            test_name: "Default + RPC + TanStack Query + Biome"
205 +
          - template: "default"
206 +
            rpc: false
207 +
            tanstackQuery: true
208 +
            router: "reactrouter"
209 +
            linter: "eslint"
210 +
            test_name: "Default + No RPC + TanStack Query + ESLint"
211 +
          - template: "default"
212 +
            rpc: false
213 +
            tanstackQuery: true
214 +
            router: "reactrouter"
215 +
            linter: "biome"
216 +
            test_name: "Default + No RPC + TanStack Query + Biome"
217 +
218 +
          # Tailwind template combinations
219 +
          - template: "tailwind"
220 +
            rpc: true
221 +
            tanstackQuery: false
222 +
            router: "reactrouter"
223 +
            linter: "eslint"
224 +
            test_name: "Tailwind + RPC + No TanStack Query + ESLint"
225 +
          - template: "tailwind"
226 +
            rpc: true
227 +
            tanstackQuery: false
228 +
            router: "reactrouter"
229 +
            linter: "biome"
230 +
            test_name: "Tailwind + RPC + No TanStack Query + Biome"
231 +
          - template: "tailwind"
232 +
            rpc: false
233 +
            tanstackQuery: false
234 +
            router: "reactrouter"
235 +
            linter: "eslint"
236 +
            test_name: "Tailwind + No RPC + No TanStack Query + ESLint"
237 +
          - template: "tailwind"
238 +
            rpc: false
239 +
            tanstackQuery: false
240 +
            router: "reactrouter"
241 +
            linter: "biome"
242 +
            test_name: "Tailwind + No RPC + No TanStack Query + Biome"
243 +
          - template: "tailwind"
244 +
            rpc: true
245 +
            tanstackQuery: true
246 +
            router: "reactrouter"
247 +
            linter: "eslint"
248 +
            test_name: "Tailwind + RPC + TanStack Query + ESLint"
249 +
          - template: "tailwind"
250 +
            rpc: true
251 +
            tanstackQuery: true
252 +
            router: "reactrouter"
253 +
            linter: "biome"
254 +
            test_name: "Tailwind + RPC + TanStack Query + Biome"
255 +
          - template: "tailwind"
256 +
            rpc: false
257 +
            tanstackQuery: true
258 +
            router: "reactrouter"
259 +
            linter: "eslint"
260 +
            test_name: "Tailwind + No RPC + TanStack Query + ESLint"
261 +
          - template: "tailwind"
262 +
            rpc: false
263 +
            tanstackQuery: true
264 +
            router: "reactrouter"
265 +
            linter: "biome"
266 +
            test_name: "Tailwind + No RPC + TanStack Query + Biome"
267 +
268 +
          # Shadcn template combinations
269 +
          - template: "shadcn"
270 +
            rpc: true
271 +
            tanstackQuery: false
272 +
            router: "reactrouter"
273 +
            linter: "eslint"
274 +
            test_name: "Shadcn + RPC + No TanStack Query + ESLint"
275 +
          - template: "shadcn"
276 +
            rpc: true
277 +
            tanstackQuery: false
278 +
            router: "reactrouter"
279 +
            linter: "biome"
280 +
            test_name: "Shadcn + RPC + No TanStack Query + Biome"
281 +
          - template: "shadcn"
282 +
            rpc: false
283 +
            tanstackQuery: false
284 +
            router: "reactrouter"
285 +
            linter: "eslint"
286 +
            test_name: "Shadcn + No RPC + No TanStack Query + ESLint"
287 +
          - template: "shadcn"
288 +
            rpc: false
289 +
            tanstackQuery: false
290 +
            router: "reactrouter"
291 +
            linter: "biome"
292 +
            test_name: "Shadcn + No RPC + No TanStack Query + Biome"
293 +
          - template: "shadcn"
294 +
            rpc: true
295 +
            tanstackQuery: true
296 +
            router: "reactrouter"
297 +
            linter: "eslint"
298 +
            test_name: "Shadcn + RPC + TanStack Query + ESLint"
299 +
          - template: "shadcn"
300 +
            rpc: true
301 +
            tanstackQuery: true
302 +
            router: "reactrouter"
303 +
            linter: "biome"
304 +
            test_name: "Shadcn + RPC + TanStack Query + Biome"
305 +
          - template: "shadcn"
306 +
            rpc: false
307 +
            tanstackQuery: true
308 +
            router: "reactrouter"
309 +
            linter: "eslint"
310 +
            test_name: "Shadcn + No RPC + TanStack Query + ESLint"
311 +
          - template: "shadcn"
312 +
            rpc: false
313 +
            tanstackQuery: true
314 +
            router: "reactrouter"
165 315
            linter: "biome"
166 316
            test_name: "Shadcn + No RPC + TanStack Query + Biome"
167 317
187 337
          echo "Template: ${{ matrix.template }}"
188 338
          echo "RPC: ${{ matrix.rpc }}"
189 339
          echo "Linter: ${{ matrix.linter }}"
190 -
          
340 +
191 341
          if [ "${{ matrix.rpc }}" = "true" ]; then
192 342
            ./dist/index.js test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} \
193 343
              --yes \
214 364
      - name: Verify build outputs
215 365
        run: |
216 366
          cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }}
217 -
          
367 +
218 368
          # Check that dist directories exist
219 369
          if [ ! -d "client/dist" ]; then
220 370
            echo "❌ Client build failed - dist directory not found"
221 371
            exit 1
222 372
          fi
223 -
          
373 +
224 374
          if [ ! -d "server/dist" ]; then
225 375
            echo "❌ Server build failed - dist directory not found"
226 376
            exit 1
227 377
          fi
228 -
          
378 +
229 379
          # Check for expected files
230 380
          if [ ! -f "client/dist/index.html" ]; then
231 381
            echo "❌ Client build incomplete - index.html not found"
232 382
            exit 1
233 383
          fi
234 -
          
384 +
235 385
          if [ ! -f "server/dist/index.js" ]; then
236 386
            echo "❌ Server build incomplete - index.js not found"
237 387
            exit 1
238 388
          fi
239 -
          
389 +
240 390
          echo "✅ Build verification passed for ${{ matrix.test_name }}"
241 391
242 392
      - name: Run linter on generated project
243 393
        run: |
244 394
          cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }}
245 -
          
395 +
246 396
          if [ "${{ matrix.linter }}" = "eslint" ]; then
247 397
            # Check if ESLint config exists and run it
248 398
            if [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then
src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-shadcn-tailwind-tanstackquery.tsx +70 −0
1 +
import { useState } from "react";
2 +
import beaver from "@/assets/beaver.svg";
3 +
import { Button } from "@/components/ui/button";
4 +
import { hcWithType } from "server/dist/client";
5 +
import { useMutation } from "@tanstack/react-query";
6 +
7 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
8 +
9 +
const client = hcWithType(SERVER_URL);
10 +
11 +
type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>;
12 +
13 +
function Home() {
14 +
	const [data, setData] = useState<
15 +
		Awaited<ReturnType<ResponseType["json"]>> | undefined
16 +
	>();
17 +
18 +
	const { mutate: sendRequest } = useMutation({
19 +
		mutationFn: async () => {
20 +
			try {
21 +
				const res = await client.hello.$get();
22 +
				if (!res.ok) {
23 +
					console.log("Error fetching data");
24 +
					return;
25 +
				}
26 +
				const data = await res.json();
27 +
				setData(data);
28 +
			} catch (error) {
29 +
				console.log(error);
30 +
			}
31 +
		},
32 +
	});
33 +
34 +
	return (
35 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
36 +
			<a
37 +
				href="https://github.com/stevedylandev/bhvr"
38 +
				target="_blank"
39 +
				rel="noopener"
40 +
			>
41 +
				<img
42 +
					src={beaver}
43 +
					className="w-16 h-16 cursor-pointer"
44 +
					alt="beaver logo"
45 +
				/>
46 +
			</a>
47 +
			<h1 className="text-5xl font-black">bhvr</h1>
48 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
49 +
			<p>A typesafe fullstack monorepo</p>
50 +
			<div className="flex items-center gap-4">
51 +
				<Button onClick={() => sendRequest()}>Call API</Button>
52 +
				<Button variant="secondary" asChild>
53 +
					<a target="_blank" href="https://bhvr.dev" rel="noopener">
54 +
						Docs
55 +
					</a>
56 +
				</Button>
57 +
			</div>
58 +
			{data && (
59 +
				<pre className="bg-gray-100 p-4 rounded-md">
60 +
					<code>
61 +
						Message: {data.message} <br />
62 +
						Success: {data.success.toString()}
63 +
					</code>
64 +
				</pre>
65 +
			)}
66 +
		</div>
67 +
	);
68 +
}
69 +
70 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-shadcn-tailwind.tsx +67 −0
1 +
import { useState } from "react";
2 +
import beaver from "@/assets/beaver.svg";
3 +
import { Button } from "@/components/ui/button";
4 +
import { hcWithType } from "server/dist/client";
5 +
6 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
7 +
8 +
const client = hcWithType(SERVER_URL);
9 +
10 +
type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>;
11 +
12 +
function Home() {
13 +
	const [data, setData] = useState<
14 +
		Awaited<ReturnType<ResponseType["json"]>> | undefined
15 +
	>();
16 +
17 +
	async function sendRequest() {
18 +
		try {
19 +
			const res = await client.hello.$get();
20 +
			if (!res.ok) {
21 +
				console.log("Error fetching data");
22 +
				return;
23 +
			}
24 +
			const data = await res.json();
25 +
			setData(data);
26 +
		} catch (error) {
27 +
			console.log(error);
28 +
		}
29 +
	}
30 +
31 +
	return (
32 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
33 +
			<a
34 +
				href="https://github.com/stevedylandev/bhvr"
35 +
				target="_blank"
36 +
				rel="noopener"
37 +
			>
38 +
				<img
39 +
					src={beaver}
40 +
					className="w-16 h-16 cursor-pointer"
41 +
					alt="beaver logo"
42 +
				/>
43 +
			</a>
44 +
			<h1 className="text-5xl font-black">bhvr</h1>
45 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
46 +
			<p>A typesafe fullstack monorepo</p>
47 +
			<div className="flex items-center gap-4">
48 +
				<Button onClick={sendRequest}>Call API</Button>
49 +
				<Button variant="secondary" asChild>
50 +
					<a target="_blank" href="https://bhvr.dev" rel="noopener">
51 +
						Docs
52 +
					</a>
53 +
				</Button>
54 +
			</div>
55 +
			{data && (
56 +
				<pre className="bg-gray-100 p-4 rounded-md">
57 +
					<code>
58 +
						Message: {data.message} <br />
59 +
						Success: {data.success.toString()}
60 +
					</code>
61 +
				</pre>
62 +
			)}
63 +
		</div>
64 +
	);
65 +
}
66 +
67 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-tailwind-tanstackquery.tsx +78 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import { hcWithType } from "server/dist/client";
4 +
import { useMutation } from "@tanstack/react-query";
5 +
6 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
7 +
8 +
type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>;
9 +
10 +
const client = hcWithType(SERVER_URL);
11 +
12 +
function Home() {
13 +
	const [data, setData] = useState<
14 +
		Awaited<ReturnType<ResponseType["json"]>> | undefined
15 +
	>();
16 +
17 +
	const { mutate: sendRequest } = useMutation({
18 +
		mutationFn: async () => {
19 +
			try {
20 +
				const res = await client.hello.$get();
21 +
				if (!res.ok) {
22 +
					console.log("Error fetching data");
23 +
					return;
24 +
				}
25 +
				const data = await res.json();
26 +
				setData(data);
27 +
			} catch (error) {
28 +
				console.log(error);
29 +
			}
30 +
		},
31 +
	});
32 +
33 +
	return (
34 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
35 +
			<a
36 +
				href="https://github.com/stevedylandev/bhvr"
37 +
				target="_blank"
38 +
				rel="noopener"
39 +
			>
40 +
				<img
41 +
					src={beaver}
42 +
					className="w-16 h-16 cursor-pointer"
43 +
					alt="beaver logo"
44 +
				/>
45 +
			</a>
46 +
			<h1 className="text-5xl font-black">bhvr</h1>
47 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
48 +
			<p>A typesafe fullstack monorepo</p>
49 +
			<div className="flex items-center gap-4">
50 +
				<button
51 +
					type="button"
52 +
					onClick={() => sendRequest()}
53 +
					className="bg-black text-white px-2.5 py-1.5 rounded-md"
54 +
				>
55 +
					Call API
56 +
				</button>
57 +
				<a
58 +
					target="_blank"
59 +
					href="https://bhvr.dev"
60 +
					className="border-1 border-black text-black px-2.5 py-1.5 rounded-md"
61 +
					rel="noopener"
62 +
				>
63 +
					Docs
64 +
				</a>
65 +
			</div>
66 +
			{data && (
67 +
				<pre className="bg-gray-100 p-4 rounded-md">
68 +
					<code>
69 +
						Message: {data.message} <br />
70 +
						Success: {data.success.toString()}
71 +
					</code>
72 +
				</pre>
73 +
			)}
74 +
		</div>
75 +
	);
76 +
}
77 +
78 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-tailwind.tsx +75 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import { hcWithType } from "server/dist/client";
4 +
5 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
6 +
7 +
type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>;
8 +
9 +
const client = hcWithType(SERVER_URL);
10 +
11 +
function Home() {
12 +
	const [data, setData] = useState<
13 +
		Awaited<ReturnType<ResponseType["json"]>> | undefined
14 +
	>();
15 +
16 +
	async function sendRequest() {
17 +
		try {
18 +
			const res = await client.hello.$get();
19 +
			if (!res.ok) {
20 +
				console.log("Error fetching data");
21 +
				return;
22 +
			}
23 +
			const data = await res.json();
24 +
			setData(data);
25 +
		} catch (error) {
26 +
			console.log(error);
27 +
		}
28 +
	}
29 +
30 +
	return (
31 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
32 +
			<a
33 +
				href="https://github.com/stevedylandev/bhvr"
34 +
				target="_blank"
35 +
				rel="noopener"
36 +
			>
37 +
				<img
38 +
					src={beaver}
39 +
					className="w-16 h-16 cursor-pointer"
40 +
					alt="beaver logo"
41 +
				/>
42 +
			</a>
43 +
			<h1 className="text-5xl font-black">bhvr</h1>
44 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
45 +
			<p>A typesafe fullstack monorepo</p>
46 +
			<div className="flex items-center gap-4">
47 +
				<button
48 +
					type="button"
49 +
					onClick={sendRequest}
50 +
					className="bg-black text-white px-2.5 py-1.5 rounded-md"
51 +
				>
52 +
					Call API
53 +
				</button>
54 +
				<a
55 +
					target="_blank"
56 +
					href="https://bhvr.dev"
57 +
					className="border-1 border-black text-black px-2.5 py-1.5 rounded-md"
58 +
					rel="noopener"
59 +
				>
60 +
					Docs
61 +
				</a>
62 +
			</div>
63 +
			{data && (
64 +
				<pre className="bg-gray-100 p-4 rounded-md">
65 +
					<code>
66 +
						Message: {data.message} <br />
67 +
						Success: {data.success.toString()}
68 +
					</code>
69 +
				</pre>
70 +
			)}
71 +
		</div>
72 +
	);
73 +
}
74 +
75 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-rpc-tanstackquery.tsx +75 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import { hcWithType } from "server/dist/client";
4 +
import { useMutation } from "@tanstack/react-query";
5 +
import "../App.css";
6 +
7 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
8 +
9 +
const client = hcWithType(SERVER_URL);
10 +
11 +
type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>;
12 +
13 +
function Home() {
14 +
	const [data, setData] = useState<
15 +
		Awaited<ReturnType<ResponseType["json"]>> | undefined
16 +
	>();
17 +
18 +
	const { mutate: sendRequest } = useMutation({
19 +
		mutationFn: async () => {
20 +
			try {
21 +
				const res = await client.hello.$get();
22 +
				if (!res.ok) {
23 +
					console.log("Error fetching data");
24 +
					return;
25 +
				}
26 +
				const data = await res.json();
27 +
				setData(data);
28 +
			} catch (error) {
29 +
				console.log(error);
30 +
			}
31 +
		},
32 +
	});
33 +
34 +
	return (
35 +
		<>
36 +
			<div>
37 +
				<a
38 +
					href="https://github.com/stevedylandev/bhvr"
39 +
					target="_blank"
40 +
					rel="noopener"
41 +
				>
42 +
					<img src={beaver} className="logo" alt="beaver logo" />
43 +
				</a>
44 +
			</div>
45 +
			<h1>bhvr</h1>
46 +
			<h2>Bun + Hono + Vite + React</h2>
47 +
			<p>A typesafe fullstack monorepo</p>
48 +
			<div className="card">
49 +
				<div className="button-container">
50 +
					<button type="button" onClick={() => sendRequest()}>
51 +
						Call API
52 +
					</button>
53 +
					<a
54 +
						className="docs-link"
55 +
						target="_blank"
56 +
						href="https://bhvr.dev"
57 +
						rel="noopener"
58 +
					>
59 +
						Docs
60 +
					</a>
61 +
				</div>
62 +
				{data && (
63 +
					<pre className="response">
64 +
						<code>
65 +
							Message: {data.message} <br />
66 +
							Success: {data.success.toString()}
67 +
						</code>
68 +
					</pre>
69 +
				)}
70 +
			</div>
71 +
		</>
72 +
	);
73 +
}
74 +
75 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-rpc.tsx +72 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import { hcWithType } from "server/dist/client";
4 +
import "../App.css";
5 +
6 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
7 +
8 +
const client = hcWithType(SERVER_URL);
9 +
10 +
type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>;
11 +
12 +
function Home() {
13 +
	const [data, setData] = useState<
14 +
		Awaited<ReturnType<ResponseType["json"]>> | undefined
15 +
	>();
16 +
17 +
	async function sendRequest() {
18 +
		try {
19 +
			const res = await client.hello.$get();
20 +
			if (!res.ok) {
21 +
				console.log("Error fetching data");
22 +
				return;
23 +
			}
24 +
			const data = await res.json();
25 +
			setData(data);
26 +
		} catch (error) {
27 +
			console.log(error);
28 +
		}
29 +
	}
30 +
31 +
	return (
32 +
		<>
33 +
			<div>
34 +
				<a
35 +
					href="https://github.com/stevedylandev/bhvr"
36 +
					target="_blank"
37 +
					rel="noopener"
38 +
				>
39 +
					<img src={beaver} className="logo" alt="beaver logo" />
40 +
				</a>
41 +
			</div>
42 +
			<h1>bhvr</h1>
43 +
			<h2>Bun + Hono + Vite + React</h2>
44 +
			<p>A typesafe fullstack monorepo</p>
45 +
			<div className="card">
46 +
				<div className="button-container">
47 +
					<button type="button" onClick={sendRequest}>
48 +
						Call API
49 +
					</button>
50 +
					<a
51 +
						className="docs-link"
52 +
						target="_blank"
53 +
						href="https://bhvr.dev"
54 +
						rel="noopener"
55 +
					>
56 +
						Docs
57 +
					</a>
58 +
				</div>
59 +
				{data && (
60 +
					<pre className="response">
61 +
						<code>
62 +
							Message: {data.message} <br />
63 +
							Success: {data.success.toString()}
64 +
						</code>
65 +
					</pre>
66 +
				)}
67 +
			</div>
68 +
		</>
69 +
	);
70 +
}
71 +
72 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-shadcn-tailwind-tanstackquery.tsx +60 −0
1 +
import { useState } from "react";
2 +
import beaver from "@/assets/beaver.svg";
3 +
import type { ApiResponse } from "shared";
4 +
import { Button } from "@/components/ui/button";
5 +
import { useMutation } from "@tanstack/react-query";
6 +
7 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
8 +
9 +
function Home() {
10 +
	const [data, setData] = useState<ApiResponse | undefined>();
11 +
12 +
	const { mutate: sendRequest } = useMutation({
13 +
		mutationFn: async () => {
14 +
			try {
15 +
				const req = await fetch(`${SERVER_URL}/hello`);
16 +
				const res: ApiResponse = await req.json();
17 +
				setData(res);
18 +
			} catch (error) {
19 +
				console.log(error);
20 +
			}
21 +
		},
22 +
	});
23 +
24 +
	return (
25 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
26 +
			<a
27 +
				href="https://github.com/stevedylandev/bhvr"
28 +
				target="_blank"
29 +
				rel="noopener"
30 +
			>
31 +
				<img
32 +
					src={beaver}
33 +
					className="w-16 h-16 cursor-pointer"
34 +
					alt="beaver logo"
35 +
				/>
36 +
			</a>
37 +
			<h1 className="text-5xl font-black">bhvr</h1>
38 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
39 +
			<p>A typesafe fullstack monorepo</p>
40 +
			<div className="flex items-center gap-4">
41 +
				<Button onClick={() => sendRequest()}>Call API</Button>
42 +
				<Button variant="secondary" asChild>
43 +
					<a target="_blank" href="https://bhvr.dev" rel="noopener">
44 +
						Docs
45 +
					</a>
46 +
				</Button>
47 +
			</div>
48 +
			{data && (
49 +
				<pre className="bg-gray-100 p-4 rounded-md">
50 +
					<code>
51 +
						Message: {data.message} <br />
52 +
						Success: {data.success.toString()}
53 +
					</code>
54 +
				</pre>
55 +
			)}
56 +
		</div>
57 +
	);
58 +
}
59 +
60 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-tailwind-tanstackquery.tsx +68 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import type { ApiResponse } from "shared";
4 +
import { useMutation } from "@tanstack/react-query";
5 +
6 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
7 +
8 +
function Home() {
9 +
	const [data, setData] = useState<ApiResponse | undefined>();
10 +
11 +
	const { mutate: sendRequest } = useMutation({
12 +
		mutationFn: async () => {
13 +
			try {
14 +
				const req = await fetch(`${SERVER_URL}/hello`);
15 +
				const res: ApiResponse = await req.json();
16 +
				setData(res);
17 +
			} catch (error) {
18 +
				console.log(error);
19 +
			}
20 +
		},
21 +
	});
22 +
23 +
	return (
24 +
		<div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen">
25 +
			<a
26 +
				href="https://github.com/stevedylandev/bhvr"
27 +
				target="_blank"
28 +
				rel="noopener"
29 +
			>
30 +
				<img
31 +
					src={beaver}
32 +
					className="w-16 h-16 cursor-pointer"
33 +
					alt="beaver logo"
34 +
				/>
35 +
			</a>
36 +
			<h1 className="text-5xl font-black">bhvr</h1>
37 +
			<h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2>
38 +
			<p>A typesafe fullstack monorepo</p>
39 +
			<div className="flex items-center gap-4">
40 +
				<button
41 +
					type="button"
42 +
					onClick={() => sendRequest()}
43 +
					className="bg-black text-white px-2.5 py-1.5 rounded-md"
44 +
				>
45 +
					Call API
46 +
				</button>
47 +
				<a
48 +
					target="_blank"
49 +
					href="https://bhvr.dev"
50 +
					className="border-1 border-black text-black px-2.5 py-1.5 rounded-md"
51 +
					rel="noopener"
52 +
				>
53 +
					Docs
54 +
				</a>
55 +
			</div>
56 +
			{data && (
57 +
				<pre className="bg-gray-100 p-4 rounded-md">
58 +
					<code>
59 +
						Message: {data.message} <br />
60 +
						Success: {data.success.toString()}
61 +
					</code>
62 +
				</pre>
63 +
			)}
64 +
		</div>
65 +
	);
66 +
}
67 +
68 +
export default Home;
src/templates/extras/client/src/components/Home.tsx/Home-with-tanstackquery.tsx +62 −0
1 +
import { useState } from "react";
2 +
import beaver from "../assets/beaver.svg";
3 +
import { useMutation } from "@tanstack/react-query";
4 +
import type { ApiResponse } from "shared";
5 +
import "../App.css";
6 +
7 +
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000";
8 +
9 +
function Home() {
10 +
	const [data, setData] = useState<ApiResponse | undefined>();
11 +
12 +
	const { mutate: sendRequest } = useMutation({
13 +
		mutationFn: async () => {
14 +
			const req = await fetch(`${SERVER_URL}/hello`);
15 +
			const res: ApiResponse = await req.json();
16 +
			setData(res);
17 +
		},
18 +
		onError: (err) => console.log(err),
19 +
	});
20 +
21 +
	return (
22 +
		<>
23 +
			<div>
24 +
				<a
25 +
					href="https://github.com/stevedylandev/bhvr"
26 +
					target="_blank"
27 +
					rel="noopener"
28 +
				>
29 +
					<img src={beaver} className="logo" alt="beaver logo" />
30 +
				</a>
31 +
			</div>
32 +
			<h1>bhvr</h1>
33 +
			<h2>Bun + Hono + Vite + React</h2>
34 +
			<p>A typesafe fullstack monorepo</p>
35 +
			<div className="card">
36 +
				<div className="button-container">
37 +
					<button type="button" onClick={() => sendRequest()}>
38 +
						Call API
39 +
					</button>
40 +
					<a
41 +
						className="docs-link"
42 +
						target="_blank"
43 +
						href="https://bhvr.dev"
44 +
						rel="noopener"
45 +
					>
46 +
						Docs
47 +
					</a>
48 +
				</div>
49 +
				{data && (
50 +
					<pre className="response">
51 +
						<code>
52 +
							Message: {data.message} <br />
53 +
							Success: {data.success.toString()}
54 +
						</code>
55 +
					</pre>
56 +
				)}
57 +
			</div>
58 +
		</>
59 +
	);
60 +
}
61 +
62 +
export default Home;