1import { createFileRoute } from "@tanstack/react-router";
2import { createServerFn } from "@tanstack/react-start";
3import { getLatestPosts } from "../prisma/queries";
4
5const getRuntime = createServerFn({ method: "GET" }).handler(async () => {
6 const posts = await getLatestPosts(10);
7 return {
8 databaseReady: Boolean(process.env.DATABASE_URL),
9 configurationReady: process.env.TANSTACK_SHARED_FLAG === "project-level",
10 message: process.env.TANSTACK_MESSAGE ?? "missing message",
11 posts: posts.map((post) => ({
12 title: post.title,
13 excerpt: post.excerpt,
14 })),
15 };
16});
17
18export const Route = createFileRoute("/")({
19 loader: () => getRuntime(),
20 component: Home,
21});
22
23function Home() {
24 const runtime = Route.useLoaderData();
25
26 return (
27 <main
28 style={{
29 minHeight: "100vh",
30 padding: "48px 20px",
31 fontFamily:
32 'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
33 background: "#f7f8fb",
34 color: "#171923",
35 }}
36 >
37 <section
38 style={{
39 width: "min(680px, 100%)",
40 margin: "0 auto",
41 display: "grid",
42 gap: 20,
43 }}
44 >
45 <div>
46 <p
47 style={{
48 margin: "0 0 8px",
49 color: "#4c6fff",
50 fontSize: 13,
51 fontWeight: 700,
52 textTransform: "uppercase",
53 }}
54 >
55 Alchemy + Prisma
56 </p>
57 <h1 style={{ margin: 0, fontSize: 40, lineHeight: 1.05 }}>
58 TanStack Start with Prisma Postgres
59 </h1>
60 </div>
61
62 <dl
63 style={{
64 margin: 0,
65 display: "grid",
66 gap: 10,
67 padding: 20,
68 border: "1px solid #d9deea",
69 borderRadius: 8,
70 background: "#ffffff",
71 }}
72 >
73 <RuntimeRow label="Message" value={runtime.message} />
74 <RuntimeRow
75 label="Database"
76 value={runtime.databaseReady ? "ready" : "unavailable"}
77 />
78 <RuntimeRow
79 label="Configuration"
80 value={runtime.configurationReady ? "ready" : "unavailable"}
81 />
82 <RuntimeRow label="Posts" value={String(runtime.posts.length)} />
83 <RuntimeRow label="Health" value="/api/health" />
84 </dl>
85
86 <section
87 style={{
88 display: "grid",
89 gap: 12,
90 }}
91 >
92 <h2 style={{ margin: "12px 0 0", fontSize: 18 }}>Latest Posts</h2>
93 <div
94 style={{
95 display: "grid",
96 gap: 10,
97 }}
98 >
99 {runtime.posts.map((post) => (
100 <article
101 key={post.title}
102 style={{
103 padding: 16,
104 border: "1px solid #d9deea",
105 borderRadius: 8,
106 background: "#ffffff",
107 }}
108 >
109 <h3 style={{ margin: "0 0 6px", fontSize: 15 }}>
110 {post.title}
111 </h3>
112 <p style={{ margin: 0, color: "#4a5568", fontSize: 13 }}>
113 {post.excerpt}
114 </p>
115 </article>
116 ))}
117 </div>
118 </section>
119 </section>
120 </main>
121 );
122}
123
124function RuntimeRow(props: Readonly<{ label: string; value: string }>) {
125 return (
126 <div
127 style={{
128 display: "grid",
129 gridTemplateColumns: "120px minmax(0, 1fr)",
130 gap: 12,
131 alignItems: "baseline",
132 }}
133 >
134 <dt style={{ color: "#667085", fontSize: 13 }}>{props.label}</dt>
135 <dd
136 style={{
137 margin: 0,
138 minWidth: 0,
139 overflowWrap: "anywhere",
140 fontFamily:
141 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace',
142 fontSize: 13,
143 }}
144 >
145 {props.value}
146 </dd>
147 </div>
148 );
149}