kaddidlehopper 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/CONTEXT.md +139 -0
  2. package/README.md +47 -0
  3. package/add-ons/ai/README.md +34 -0
  4. package/add-ons/ai/assets/_dot_env.local.append +13 -0
  5. package/add-ons/ai/assets/src/components/AIAssistant.tsx +149 -0
  6. package/add-ons/ai/assets/src/lib/ai-hook.ts +21 -0
  7. package/add-ons/ai/assets/src/lib/weather-tools.ts +30 -0
  8. package/add-ons/ai/assets/src/routes/api.chat.ts +94 -0
  9. package/add-ons/ai/assets/src/routes/chat.css +175 -0
  10. package/add-ons/ai/assets/src/routes/chat.tsx +141 -0
  11. package/add-ons/ai/info.json +27 -0
  12. package/add-ons/ai/package.json +17 -0
  13. package/add-ons/ai/small-logo.svg +8 -0
  14. package/dist/cli.js +251 -0
  15. package/dist/index.js +33 -0
  16. package/dist/types/cli.d.ts +8 -0
  17. package/dist/types/index.d.ts +2 -0
  18. package/dist/types/types.d.ts +14 -0
  19. package/dist/types.js +1 -0
  20. package/examples/blog/README.md +60 -0
  21. package/examples/blog/assets/content/posts/beach.md +12 -0
  22. package/examples/blog/assets/content/posts/jungle.md.ejs +12 -0
  23. package/examples/blog/assets/content/posts/mountains.md.ejs +12 -0
  24. package/examples/blog/assets/content/posts/snorkeling.md.ejs +12 -0
  25. package/examples/blog/assets/content/posts/waterfall.md.ejs +12 -0
  26. package/examples/blog/assets/content-collections.ts +30 -0
  27. package/examples/blog/assets/public/beach.jpg +0 -0
  28. package/examples/blog/assets/public/jungle.jpg +0 -0
  29. package/examples/blog/assets/public/mountains.jpg +0 -0
  30. package/examples/blog/assets/public/snorkeling.jpg +0 -0
  31. package/examples/blog/assets/public/waterfall.jpg +0 -0
  32. package/examples/blog/assets/src/components/Header.tsx +52 -0
  33. package/examples/blog/assets/src/components/VacayAssistant.tsx +205 -0
  34. package/examples/blog/assets/src/components/blog-posts.tsx +78 -0
  35. package/examples/blog/assets/src/components/ui/card.tsx +92 -0
  36. package/examples/blog/assets/src/lib/blog-ai-hook.ts +25 -0
  37. package/examples/blog/assets/src/lib/blog-tools.ts +111 -0
  38. package/examples/blog/assets/src/lib/utils.ts +6 -0
  39. package/examples/blog/assets/src/routes/__root.tsx +57 -0
  40. package/examples/blog/assets/src/routes/api.blog-chat.ts +117 -0
  41. package/examples/blog/assets/src/routes/category.$category.tsx +19 -0
  42. package/examples/blog/assets/src/routes/index.tsx +19 -0
  43. package/examples/blog/assets/src/routes/posts.$slug.tsx +63 -0
  44. package/examples/blog/assets/src/styles.css +138 -0
  45. package/examples/blog/info.json +43 -0
  46. package/examples/blog/package.json +23 -0
  47. package/examples/events/README.md +110 -0
  48. package/examples/events/assets/content/speakers/andre-costa.md +22 -0
  49. package/examples/events/assets/content/speakers/hans-mueller.md.ejs +22 -0
  50. package/examples/events/assets/content/speakers/isabella-martinez.md.ejs +22 -0
  51. package/examples/events/assets/content/speakers/kenji-nakamura.md.ejs +22 -0
  52. package/examples/events/assets/content/speakers/marie-dubois.md.ejs +20 -0
  53. package/examples/events/assets/content/speakers/priya-sharma.md.ejs +22 -0
  54. package/examples/events/assets/content/talks/croissant-lamination-secrets.md +39 -0
  55. package/examples/events/assets/content/talks/french-macaron-mastery.md.ejs +39 -0
  56. package/examples/events/assets/content/talks/neapolitan-pizza-tradition-meets-innovation.md.ejs +39 -0
  57. package/examples/events/assets/content/talks/savory-breads-of-the-mediterranean.md.ejs +39 -0
  58. package/examples/events/assets/content/talks/sourdough-from-starter-to-masterpiece.md.ejs +36 -0
  59. package/examples/events/assets/content/talks/the-art-of-the-perfect-tart.md.ejs +32 -0
  60. package/examples/events/assets/content/talks/the-science-of-sugar.md.ejs +39 -0
  61. package/examples/events/assets/content/talks/umami-in-pastry-east-meets-west.md.ejs +39 -0
  62. package/examples/events/assets/content-collections.ts +56 -0
  63. package/examples/events/assets/public/background-1.jpg +0 -0
  64. package/examples/events/assets/public/background-2.jpg +0 -0
  65. package/examples/events/assets/public/background-3.jpg +0 -0
  66. package/examples/events/assets/public/background-4.jpg +0 -0
  67. package/examples/events/assets/public/conference-logo.png +0 -0
  68. package/examples/events/assets/public/favicon.ico +0 -0
  69. package/examples/events/assets/public/speakers/andre-costa.jpg +0 -0
  70. package/examples/events/assets/public/speakers/hans-mueller.jpg +0 -0
  71. package/examples/events/assets/public/speakers/isabella-martinez.jpg +0 -0
  72. package/examples/events/assets/public/speakers/kenji-nakamura.jpg +0 -0
  73. package/examples/events/assets/public/speakers/marie-dubois.jpg +0 -0
  74. package/examples/events/assets/public/speakers/priya-sharma.jpg +0 -0
  75. package/examples/events/assets/public/talks/croissant-lamination-secrets.jpg +0 -0
  76. package/examples/events/assets/public/talks/french-macaron-mastery.jpg +0 -0
  77. package/examples/events/assets/public/talks/neapolitan-pizza-tradition-meets-innovation.jpg +0 -0
  78. package/examples/events/assets/public/talks/savory-breads-of-the-mediterranean.jpg +0 -0
  79. package/examples/events/assets/public/talks/sourdough-from-starter-to-masterpiece.jpg +0 -0
  80. package/examples/events/assets/public/talks/the-art-of-the-perfect-tart.jpg +0 -0
  81. package/examples/events/assets/public/talks/the-science-of-sugar.jpg +0 -0
  82. package/examples/events/assets/public/talks/umami-in-pastry-east-meets-west.jpg +0 -0
  83. package/examples/events/assets/public/tanstack-circle-logo.png +0 -0
  84. package/examples/events/assets/public/tanstack-word-logo-white.svg +1 -0
  85. package/examples/events/assets/src/components/Header.tsx +59 -0
  86. package/examples/events/assets/src/components/HeaderNav.tsx +67 -0
  87. package/examples/events/assets/src/components/HeroCarousel.tsx +61 -0
  88. package/examples/events/assets/src/components/RemyAssistant.tsx +207 -0
  89. package/examples/events/assets/src/components/SpeakerCard.tsx +67 -0
  90. package/examples/events/assets/src/components/TalkCard.tsx +77 -0
  91. package/examples/events/assets/src/components/ui/card.tsx +92 -0
  92. package/examples/events/assets/src/lib/conference-ai-hook.ts +26 -0
  93. package/examples/events/assets/src/lib/conference-tools.ts +210 -0
  94. package/examples/events/assets/src/lib/model-selection.ts +1 -0
  95. package/examples/events/assets/src/lib/utils.ts +6 -0
  96. package/examples/events/assets/src/routes/__root.tsx +70 -0
  97. package/examples/events/assets/src/routes/api.remy-chat.ts +119 -0
  98. package/examples/events/assets/src/routes/index.tsx +192 -0
  99. package/examples/events/assets/src/routes/schedule.index.tsx +274 -0
  100. package/examples/events/assets/src/routes/speakers.$slug.tsx +122 -0
  101. package/examples/events/assets/src/routes/speakers.index.tsx +40 -0
  102. package/examples/events/assets/src/routes/talks.$slug.tsx +116 -0
  103. package/examples/events/assets/src/routes/talks.index.tsx +40 -0
  104. package/examples/events/assets/src/styles.css +182 -0
  105. package/examples/events/info.json +74 -0
  106. package/examples/events/package.json +23 -0
  107. package/examples/marketing/README.md +60 -0
  108. package/examples/marketing/assets/public/logo.png +0 -0
  109. package/examples/marketing/assets/public/motorcycle-adventure.jpg +0 -0
  110. package/examples/marketing/assets/public/motorcycle-cruiser.jpg +0 -0
  111. package/examples/marketing/assets/public/motorcycle-scooter.jpg +0 -0
  112. package/examples/marketing/assets/public/motorcycle-sport.jpg +0 -0
  113. package/examples/marketing/assets/public/motorcycle-supersport.jpg +0 -0
  114. package/examples/marketing/assets/src/components/Header.tsx +36 -0
  115. package/examples/marketing/assets/src/components/MotorcycleAIAssistant.tsx +162 -0
  116. package/examples/marketing/assets/src/components/MotorcycleRecommendation.tsx +53 -0
  117. package/examples/marketing/assets/src/data/motorcycles.ts.ejs +77 -0
  118. package/examples/marketing/assets/src/lib/motorcycle-ai-hook.ts +24 -0
  119. package/examples/marketing/assets/src/lib/motorcycle-tools.ts +42 -0
  120. package/examples/marketing/assets/src/routes/__root.tsx +57 -0
  121. package/examples/marketing/assets/src/routes/api.motorcycle-chat.ts +78 -0
  122. package/examples/marketing/assets/src/routes/index.tsx +72 -0
  123. package/examples/marketing/assets/src/routes/motorcycles/$motorcycleId.tsx +56 -0
  124. package/examples/marketing/assets/src/store/motorcycle-assistant.ts +3 -0
  125. package/examples/marketing/assets/src/styles.css +212 -0
  126. package/examples/marketing/info.json +38 -0
  127. package/examples/marketing/package.json +14 -0
  128. package/examples/resume/README.md +82 -0
  129. package/examples/resume/assets/content/education/code-school.md +17 -0
  130. package/examples/resume/assets/content/jobs/freelance.md.ejs +13 -0
  131. package/examples/resume/assets/content/jobs/initech-junior.md +20 -0
  132. package/examples/resume/assets/content/jobs/initech-lead.md.ejs +29 -0
  133. package/examples/resume/assets/content/jobs/initrode-senior.md.ejs +28 -0
  134. package/examples/resume/assets/content-collections.ts +36 -0
  135. package/examples/resume/assets/public/headshot-on-white.jpg +0 -0
  136. package/examples/resume/assets/src/components/Header.tsx +33 -0
  137. package/examples/resume/assets/src/components/ResumeAssistant.tsx +193 -0
  138. package/examples/resume/assets/src/components/ui/badge.tsx +46 -0
  139. package/examples/resume/assets/src/components/ui/card.tsx +92 -0
  140. package/examples/resume/assets/src/components/ui/checkbox.tsx +30 -0
  141. package/examples/resume/assets/src/components/ui/hover-card.tsx +44 -0
  142. package/examples/resume/assets/src/components/ui/separator.tsx +26 -0
  143. package/examples/resume/assets/src/lib/resume-ai-hook.ts +21 -0
  144. package/examples/resume/assets/src/lib/resume-tools.ts +165 -0
  145. package/examples/resume/assets/src/lib/utils.ts +6 -0
  146. package/examples/resume/assets/src/routes/api.resume-chat.ts +110 -0
  147. package/examples/resume/assets/src/routes/index.tsx +220 -0
  148. package/examples/resume/assets/src/styles.css +138 -0
  149. package/examples/resume/info.json +25 -0
  150. package/examples/resume/package.json +26 -0
  151. package/package.json +39 -0
  152. package/project/base/_dot_claude/skills/content-collections/SKILL.md +505 -0
  153. package/project/base/_dot_claude/skills/netlify-blobs/SKILL.md +410 -0
  154. package/project/base/_dot_claude/skills/netlify-db/SKILL.md +424 -0
  155. package/project/base/_dot_claude/skills/netlify-debugging/SKILL.md +419 -0
  156. package/project/base/_dot_claude/skills/netlify-forms/SKILL.md +243 -0
  157. package/project/base/_dot_claude/skills/netlify-functions/SKILL.md +372 -0
  158. package/project/base/_dot_claude/skills/tanstack-start-api-routes/SKILL.md +421 -0
  159. package/project/base/_dot_claude/skills/tanstack-start-loaders/SKILL.md +426 -0
  160. package/project/base/_dot_claude/skills/tanstack-start-project-setup/SKILL.md +493 -0
  161. package/project/base/_dot_claude/skills/tanstack-start-routes/SKILL.md +430 -0
  162. package/project/base/_dot_claude/skills/tanstack-start-server-functions/SKILL.md +445 -0
  163. package/project/base/_dot_claude/skills/tanstack-start-typesafe-routing/SKILL.md +494 -0
  164. package/project/base/_dot_gitignore +8 -0
  165. package/project/base/netlify.toml +7 -0
  166. package/project/base/package.json +33 -0
  167. package/project/base/public/favicon.ico +0 -0
  168. package/project/base/public/tanstack-circle-logo.png +0 -0
  169. package/project/base/public/tanstack-word-logo-white.svg +1 -0
  170. package/project/base/src/components/Header.tsx +17 -0
  171. package/project/base/src/components/HeaderNav.tsx.ejs +179 -0
  172. package/project/base/src/router.tsx +15 -0
  173. package/project/base/src/routes/__root.tsx +57 -0
  174. package/project/base/src/routes/index.tsx +48 -0
  175. package/project/base/src/styles.css +15 -0
  176. package/project/base/tsconfig.json +28 -0
  177. package/project/base/vite.config.ts.ejs +25 -0
  178. package/project/packages.json +22 -0
  179. package/scripts/check-outdated-packages.js +421 -0
  180. package/src/cli.ts +343 -0
  181. package/src/index.ts +49 -0
  182. package/src/types.ts +15 -0
  183. package/tsconfig.json +17 -0
@@ -0,0 +1,430 @@
1
+ ---
2
+ name: tanstack-start-routes
3
+ description: Create and manage routes in TanStack Start using file-based routing. Use when adding new pages, configuring layouts, setting up nested routes, or working with route parameters.
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: tanstack
7
+ version: "1.0"
8
+ ---
9
+
10
+ # TanStack Start Routes
11
+
12
+ TanStack Start uses file-based routing with TanStack Router. Routes are defined as files in the `src/routes` directory.
13
+
14
+ ## When to Use
15
+
16
+ - Adding new pages to your application
17
+ - Setting up nested layouts
18
+ - Configuring route parameters
19
+ - Creating pathless layout routes
20
+ - Organizing route structure
21
+
22
+ ## Directory Structure
23
+
24
+ ```
25
+ src/
26
+ ├── routes/
27
+ │ ├── __root.tsx # Root layout (required)
28
+ │ ├── index.tsx # Home page (/)
29
+ │ ├── about.tsx # About page (/about)
30
+ │ ├── posts.tsx # Posts layout (/posts)
31
+ │ ├── posts.index.tsx # Posts index (/posts)
32
+ │ ├── posts.$postId.tsx # Dynamic post (/posts/:postId)
33
+ │ ├── _auth.tsx # Pathless layout (no URL segment)
34
+ │ ├── _auth.login.tsx # Login under auth layout (/login)
35
+ │ └── _auth.register.tsx # Register under auth layout (/register)
36
+ ├── router.tsx # Router configuration
37
+ └── routeTree.gen.ts # Auto-generated route tree
38
+ ```
39
+
40
+ ## Root Route
41
+
42
+ The root route wraps all other routes and defines the document shell:
43
+
44
+ ```tsx
45
+ // src/routes/__root.tsx
46
+ import {
47
+ Outlet,
48
+ createRootRoute,
49
+ HeadContent,
50
+ Scripts
51
+ } from '@tanstack/react-router';
52
+ import type { ReactNode } from 'react';
53
+
54
+ export const Route = createRootRoute({
55
+ head: () => ({
56
+ meta: [
57
+ { charSet: 'utf-8' },
58
+ { name: 'viewport', content: 'width=device-width, initial-scale=1' },
59
+ { title: 'My App' },
60
+ ],
61
+ }),
62
+ component: RootComponent,
63
+ });
64
+
65
+ function RootComponent() {
66
+ return (
67
+ <html>
68
+ <head>
69
+ <HeadContent />
70
+ </head>
71
+ <body>
72
+ <Header />
73
+ <main>
74
+ <Outlet />
75
+ </main>
76
+ <Scripts />
77
+ </body>
78
+ </html>
79
+ );
80
+ }
81
+
82
+ function Header() {
83
+ return (
84
+ <header>
85
+ <nav>
86
+ <Link to="/">Home</Link>
87
+ <Link to="/about">About</Link>
88
+ <Link to="/posts">Posts</Link>
89
+ </nav>
90
+ </header>
91
+ );
92
+ }
93
+ ```
94
+
95
+ ## Basic Route
96
+
97
+ ```tsx
98
+ // src/routes/about.tsx
99
+ import { createFileRoute } from '@tanstack/react-router';
100
+
101
+ export const Route = createFileRoute('/about')({
102
+ component: AboutComponent,
103
+ });
104
+
105
+ function AboutComponent() {
106
+ return (
107
+ <div>
108
+ <h1>About Us</h1>
109
+ <p>This is the about page.</p>
110
+ </div>
111
+ );
112
+ }
113
+ ```
114
+
115
+ ## Index Route
116
+
117
+ Index routes render when the parent path is matched exactly:
118
+
119
+ ```tsx
120
+ // src/routes/index.tsx (renders at /)
121
+ import { createFileRoute } from '@tanstack/react-router';
122
+
123
+ export const Route = createFileRoute('/')({
124
+ component: HomeComponent,
125
+ });
126
+
127
+ function HomeComponent() {
128
+ return <h1>Welcome Home</h1>;
129
+ }
130
+ ```
131
+
132
+ ```tsx
133
+ // src/routes/posts.index.tsx (renders at /posts)
134
+ import { createFileRoute } from '@tanstack/react-router';
135
+
136
+ export const Route = createFileRoute('/posts/')({
137
+ component: PostsIndexComponent,
138
+ });
139
+
140
+ function PostsIndexComponent() {
141
+ return <h2>Select a post from the list</h2>;
142
+ }
143
+ ```
144
+
145
+ ## Layout Routes
146
+
147
+ Layout routes wrap child routes with shared UI:
148
+
149
+ ```tsx
150
+ // src/routes/posts.tsx
151
+ import { createFileRoute, Outlet, Link } from '@tanstack/react-router';
152
+
153
+ export const Route = createFileRoute('/posts')({
154
+ component: PostsLayoutComponent,
155
+ });
156
+
157
+ function PostsLayoutComponent() {
158
+ return (
159
+ <div className="posts-layout">
160
+ <aside>
161
+ <h2>Posts</h2>
162
+ <nav>
163
+ <Link to="/posts/1">Post 1</Link>
164
+ <Link to="/posts/2">Post 2</Link>
165
+ </nav>
166
+ </aside>
167
+ <div className="content">
168
+ <Outlet /> {/* Child routes render here */}
169
+ </div>
170
+ </div>
171
+ );
172
+ }
173
+ ```
174
+
175
+ ## Dynamic Route Parameters
176
+
177
+ Use `$paramName` for dynamic segments:
178
+
179
+ ```tsx
180
+ // src/routes/posts.$postId.tsx
181
+ import { createFileRoute } from '@tanstack/react-router';
182
+
183
+ export const Route = createFileRoute('/posts/$postId')({
184
+ component: PostComponent,
185
+ });
186
+
187
+ function PostComponent() {
188
+ const { postId } = Route.useParams();
189
+
190
+ return (
191
+ <article>
192
+ <h1>Post {postId}</h1>
193
+ </article>
194
+ );
195
+ }
196
+ ```
197
+
198
+ ### Multiple Parameters
199
+
200
+ ```tsx
201
+ // src/routes/users.$userId.posts.$postId.tsx
202
+ // Matches: /users/123/posts/456
203
+ import { createFileRoute } from '@tanstack/react-router';
204
+
205
+ export const Route = createFileRoute('/users/$userId/posts/$postId')({
206
+ component: UserPostComponent,
207
+ });
208
+
209
+ function UserPostComponent() {
210
+ const { userId, postId } = Route.useParams();
211
+
212
+ return <div>User {userId}'s Post {postId}</div>;
213
+ }
214
+ ```
215
+
216
+ ## Pathless Layout Routes
217
+
218
+ Prefix with `_` for layouts that don't add URL segments:
219
+
220
+ ```tsx
221
+ // src/routes/_auth.tsx
222
+ // This creates a layout but adds no URL segment
223
+ import { createFileRoute, Outlet, redirect } from '@tanstack/react-router';
224
+
225
+ export const Route = createFileRoute('/_auth')({
226
+ beforeLoad: async ({ context }) => {
227
+ // Redirect if already authenticated
228
+ if (context.user) {
229
+ throw redirect({ to: '/dashboard' });
230
+ }
231
+ },
232
+ component: AuthLayout,
233
+ });
234
+
235
+ function AuthLayout() {
236
+ return (
237
+ <div className="auth-container">
238
+ <div className="auth-card">
239
+ <Outlet />
240
+ </div>
241
+ </div>
242
+ );
243
+ }
244
+ ```
245
+
246
+ ```tsx
247
+ // src/routes/_auth.login.tsx
248
+ // Renders at /login (not /_auth/login)
249
+ import { createFileRoute } from '@tanstack/react-router';
250
+
251
+ export const Route = createFileRoute('/_auth/login')({
252
+ component: LoginComponent,
253
+ });
254
+
255
+ function LoginComponent() {
256
+ return <form>Login Form</form>;
257
+ }
258
+ ```
259
+
260
+ ## Catch-All (Splat) Routes
261
+
262
+ Use `$` for catch-all routes:
263
+
264
+ ```tsx
265
+ // src/routes/files.$.tsx
266
+ // Matches: /files/any/path/here
267
+ import { createFileRoute } from '@tanstack/react-router';
268
+
269
+ export const Route = createFileRoute('/files/$')({
270
+ component: FilesComponent,
271
+ });
272
+
273
+ function FilesComponent() {
274
+ const { _splat } = Route.useParams();
275
+ // _splat = "any/path/here"
276
+
277
+ return <div>File path: {_splat}</div>;
278
+ }
279
+ ```
280
+
281
+ ## 404 Not Found Route
282
+
283
+ ```tsx
284
+ // src/routes/__root.tsx
285
+ import { createRootRoute } from '@tanstack/react-router';
286
+
287
+ export const Route = createRootRoute({
288
+ component: RootComponent,
289
+ notFoundComponent: NotFoundComponent,
290
+ });
291
+
292
+ function NotFoundComponent() {
293
+ return (
294
+ <div>
295
+ <h1>404 - Page Not Found</h1>
296
+ <Link to="/">Go Home</Link>
297
+ </div>
298
+ );
299
+ }
300
+ ```
301
+
302
+ ## Route Configuration Options
303
+
304
+ ```tsx
305
+ import { createFileRoute } from '@tanstack/react-router';
306
+
307
+ export const Route = createFileRoute('/posts/$postId')({
308
+ // Component to render
309
+ component: PostComponent,
310
+
311
+ // Error boundary component
312
+ errorComponent: ErrorComponent,
313
+
314
+ // Loading/pending component
315
+ pendingComponent: LoadingComponent,
316
+
317
+ // Not found component (for this route)
318
+ notFoundComponent: NotFoundComponent,
319
+
320
+ // Validate and parse params
321
+ parseParams: (params) => ({
322
+ postId: parseInt(params.postId, 10),
323
+ }),
324
+
325
+ // Serialize params back to strings
326
+ stringifyParams: (params) => ({
327
+ postId: String(params.postId),
328
+ }),
329
+
330
+ // Validate search params
331
+ validateSearch: (search) => ({
332
+ page: Number(search.page) || 1,
333
+ }),
334
+ });
335
+ ```
336
+
337
+ ## File Naming Conventions
338
+
339
+ | File Name | Route Path |
340
+ |-----------|------------|
341
+ | `index.tsx` | `/` |
342
+ | `about.tsx` | `/about` |
343
+ | `posts.tsx` | `/posts` (layout) |
344
+ | `posts.index.tsx` | `/posts` (index) |
345
+ | `posts.$postId.tsx` | `/posts/:postId` |
346
+ | `posts.$postId.edit.tsx` | `/posts/:postId/edit` |
347
+ | `_layout.tsx` | Pathless layout |
348
+ | `_layout.page.tsx` | `/page` with layout |
349
+ | `files.$.tsx` | `/files/*` (catch-all) |
350
+
351
+ ## Directory vs Flat Routes
352
+
353
+ Both styles work and can be mixed:
354
+
355
+ **Flat (dot notation):**
356
+ ```
357
+ routes/
358
+ ├── posts.tsx
359
+ ├── posts.index.tsx
360
+ └── posts.$postId.tsx
361
+ ```
362
+
363
+ **Directory style:**
364
+ ```
365
+ routes/
366
+ └── posts/
367
+ ├── route.tsx # Layout
368
+ ├── index.tsx # Index
369
+ └── $postId.tsx # Dynamic
370
+ ```
371
+
372
+ ## Router Configuration
373
+
374
+ ```tsx
375
+ // src/router.tsx
376
+ import { createRouter } from '@tanstack/react-router';
377
+ import { routeTree } from './routeTree.gen';
378
+
379
+ export function getRouter() {
380
+ const router = createRouter({
381
+ routeTree,
382
+ scrollRestoration: true,
383
+ defaultPreload: 'intent',
384
+ defaultPreloadStaleTime: 0,
385
+ });
386
+
387
+ return router;
388
+ }
389
+
390
+ declare module '@tanstack/react-router' {
391
+ interface Register {
392
+ router: ReturnType<typeof getRouter>;
393
+ }
394
+ }
395
+ ```
396
+
397
+ ## Common Patterns
398
+
399
+ ### Protected Routes
400
+
401
+ ```tsx
402
+ // src/routes/_protected.tsx
403
+ import { createFileRoute, redirect } from '@tanstack/react-router';
404
+
405
+ export const Route = createFileRoute('/_protected')({
406
+ beforeLoad: async ({ context }) => {
407
+ if (!context.user) {
408
+ throw redirect({
409
+ to: '/login',
410
+ search: { redirect: location.href },
411
+ });
412
+ }
413
+ },
414
+ component: ProtectedLayout,
415
+ });
416
+ ```
417
+
418
+ ### Route Groups (Organization Only)
419
+
420
+ Use parentheses for grouping without affecting URLs:
421
+
422
+ ```
423
+ routes/
424
+ ├── (marketing)/
425
+ │ ├── about.tsx # /about
426
+ │ └── pricing.tsx # /pricing
427
+ └── (app)/
428
+ ├── dashboard.tsx # /dashboard
429
+ └── settings.tsx # /settings
430
+ ```