@thorprovider/create-storefront 0.1.1

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 (75) hide show
  1. package/README.md +119 -0
  2. package/bin/install.js +116 -0
  3. package/commands/sf-add-view.md +21 -0
  4. package/commands/sf-init.md +16 -0
  5. package/commands/sf-theme.md +15 -0
  6. package/commands/sf-view.md +20 -0
  7. package/package.json +40 -0
  8. package/recipes/archetype.schema.json +39 -0
  9. package/recipes/archetypes.json +148 -0
  10. package/recipes/recipe.schema.json +59 -0
  11. package/recipes/recipes.json +90 -0
  12. package/recipes/sections.json +46 -0
  13. package/recipes/validate.mjs +190 -0
  14. package/skills/building-storefronts/SKILL.md +178 -0
  15. package/skills/building-storefronts/references/frontend-integration.md +229 -0
  16. package/skills/json-render-core/SKILL.md +291 -0
  17. package/skills/json-render-next/SKILL.md +194 -0
  18. package/skills/json-render-react/SKILL.md +298 -0
  19. package/skills/json-render-remotion/SKILL.md +111 -0
  20. package/skills/json-render-shadcn/SKILL.md +159 -0
  21. package/skills/json-render-solid/SKILL.md +204 -0
  22. package/skills/nextjs-shadcn/SKILL.md +303 -0
  23. package/skills/nextjs-shadcn/references/architecture.md +499 -0
  24. package/skills/nextjs-shadcn/references/project-setup.md +127 -0
  25. package/skills/nextjs-shadcn/references/shadcn-platform.md +258 -0
  26. package/skills/nextjs-shadcn/references/sidebar.md +274 -0
  27. package/skills/nextjs-shadcn/references/styling.md +555 -0
  28. package/skills/sf-scaffold/SKILL.md +118 -0
  29. package/skills/sf-theme-gen/SKILL.md +44 -0
  30. package/skills/sf-view-gen/SKILL.md +94 -0
  31. package/skills/shadcn-component-discovery/SKILL.md +273 -0
  32. package/skills/shadcn-component-discovery/references/registries.md +226 -0
  33. package/skills/shadcn-theming/SKILL.md +104 -0
  34. package/skills/shadcn-theming/references/templates/theme-setup.md +109 -0
  35. package/skills/shadcn-theming/references/theming-guide.md +90 -0
  36. package/skills/storefront-best-practices/SKILL.md +421 -0
  37. package/skills/storefront-best-practices/reference/components/breadcrumbs.md +123 -0
  38. package/skills/storefront-best-practices/reference/components/cart-popup.md +189 -0
  39. package/skills/storefront-best-practices/reference/components/country-selector.md +298 -0
  40. package/skills/storefront-best-practices/reference/components/footer.md +112 -0
  41. package/skills/storefront-best-practices/reference/components/hero.md +241 -0
  42. package/skills/storefront-best-practices/reference/components/megamenu.md +239 -0
  43. package/skills/storefront-best-practices/reference/components/navbar.md +397 -0
  44. package/skills/storefront-best-practices/reference/components/popups.md +221 -0
  45. package/skills/storefront-best-practices/reference/components/product-card.md +125 -0
  46. package/skills/storefront-best-practices/reference/components/product-reviews.md +217 -0
  47. package/skills/storefront-best-practices/reference/components/product-slider.md +174 -0
  48. package/skills/storefront-best-practices/reference/components/search.md +101 -0
  49. package/skills/storefront-best-practices/reference/connecting-to-backend.md +391 -0
  50. package/skills/storefront-best-practices/reference/design.md +388 -0
  51. package/skills/storefront-best-practices/reference/features/promotions.md +307 -0
  52. package/skills/storefront-best-practices/reference/features/wishlist.md +230 -0
  53. package/skills/storefront-best-practices/reference/layouts/account.md +380 -0
  54. package/skills/storefront-best-practices/reference/layouts/cart.md +316 -0
  55. package/skills/storefront-best-practices/reference/layouts/checkout.md +486 -0
  56. package/skills/storefront-best-practices/reference/layouts/home-page.md +264 -0
  57. package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +231 -0
  58. package/skills/storefront-best-practices/reference/layouts/product-details.md +527 -0
  59. package/skills/storefront-best-practices/reference/layouts/product-listing.md +520 -0
  60. package/skills/storefront-best-practices/reference/layouts/static-pages.md +356 -0
  61. package/skills/storefront-best-practices/reference/medusa.md +307 -0
  62. package/skills/storefront-best-practices/reference/mobile-responsiveness.md +183 -0
  63. package/skills/storefront-best-practices/reference/seo.md +195 -0
  64. package/templates/app/app/[[...slug]]/page.tsx +17 -0
  65. package/templates/app/app/[[...slug]]/renderer.tsx +10 -0
  66. package/templates/app/app/globals.css +101 -0
  67. package/templates/app/app/layout.tsx +35 -0
  68. package/templates/app/lib/__STOREFRONT__/catalog.ts +132 -0
  69. package/templates/app/lib/__STOREFRONT__/handlers.ts +33 -0
  70. package/templates/app/lib/__STOREFRONT__/registry.tsx +134 -0
  71. package/templates/app/lib/__STOREFRONT__/runtime.ts +25 -0
  72. package/templates/app/lib/__STOREFRONT__/spec/home.ts +62 -0
  73. package/templates/app/lib/__STOREFRONT__/spec/index.ts +59 -0
  74. package/templates/app/lib/__STOREFRONT__/spec/types.ts +14 -0
  75. package/templates/app/lib/__STOREFRONT__/state.ts +35 -0
@@ -0,0 +1,499 @@
1
+ # Architecture
2
+
3
+ ## Best Practices
4
+
5
+ - Avoid `useEffect` - prefer Server Components, Server Actions, or event handlers
6
+ - `"use client"` only at leaf components (smallest boundary)
7
+ - Props must be serializable (data or Server Actions, no functions/classes)
8
+ - Prefer Tailwind v4 `globals.css` theme variables over hardcoded values
9
+
10
+ ## Component Patterns
11
+
12
+ ### Server vs Client Decision Tree
13
+
14
+ ```
15
+ Need state/effects/browser APIs?
16
+ ├── Yes → "use client" at smallest boundary
17
+ └── No → Server Component (default)
18
+
19
+ Passing data to client?
20
+ ├── Functions/classes → ❌ Not serializable
21
+ ├── Plain objects/arrays → ✅ Props
22
+ └── Server logic → ✅ Server Actions
23
+ ```
24
+
25
+ ### Component Placement
26
+
27
+ ```
28
+ app/
29
+ ├── (protected)/ # Auth required routes
30
+ │ ├── dashboard/
31
+ │ ├── settings/
32
+ │ ├── components/ # Route-specific components
33
+ │ └── lib/ # Route-specific types/utils
34
+ ├── (public)/ # Public routes
35
+ │ ├── login/
36
+ │ └── register/
37
+ ├── actions/ # Server Actions (global)
38
+ ├── api/ # API routes
39
+ components/ # Shared across routes
40
+ ├── ui/ # shadcn primitives
41
+ └── shared/ # Business components
42
+ hooks/ # Custom React hooks
43
+ lib/ # Shared utilities
44
+ data/ # Database queries
45
+ ai/ # AI logic (tools, agents, prompts)
46
+ ```
47
+
48
+ ### AI Directory Structure
49
+
50
+ When building AI applications, organize the `ai/` directory:
51
+
52
+ ```
53
+ ai/
54
+ ├── model-names.ts # Model definitions & DEFAULT_MODEL_NAME
55
+ ├── actions/ # AI-related server actions
56
+ │ ├── model.ts # saveModelId, getModelId (cookie-based)
57
+ │ └── chat.ts # Chat-related actions
58
+ ├── utils.ts # findSources, getLastUserMessageText, etc.
59
+ ├── agents/ # Agent definitions (if using agents)
60
+ │ └── assistant.ts
61
+ └── tools/ # Tool definitions (if using tools)
62
+ ```
63
+
64
+ **model-names.ts example:**
65
+
66
+ ```ts
67
+ export interface Model {
68
+ id: string
69
+ label: string
70
+ description: string
71
+ }
72
+
73
+ export const models: Model[] = [
74
+ { id: "gpt-5.6-luna", label: "GPT 5.6 Luna", description: "Fast, lightweight tasks" },
75
+ { id: "gpt-5.6", label: "GPT 5.6", description: "Complex, multi-step tasks" },
76
+ ]
77
+
78
+ export const DEFAULT_MODEL_NAME = "gpt-5.6-luna"
79
+ ```
80
+
81
+ **Cookie-based model storage:**
82
+
83
+ ```ts
84
+ // ai/actions/model.ts - Server Action for MUTATION only
85
+ "use server"
86
+ import { cookies } from "next/headers"
87
+
88
+ export async function saveModelId(model: string) {
89
+ const cookieStore = await cookies()
90
+ cookieStore.set("model-id", model)
91
+ }
92
+
93
+ // ❌ WRONG: Don't use Server Action for reading data
94
+ // export async function getModelId() { ... }
95
+
96
+ // ✅ CORRECT: Read cookies directly in Server Component
97
+ // page.tsx
98
+ import { cookies } from "next/headers"
99
+
100
+ export default async function Page() {
101
+ const cookieStore = await cookies()
102
+ const modelId = cookieStore.get("model-id")?.value ?? DEFAULT_MODEL_NAME
103
+ return <Chat modelId={modelId} />
104
+ }
105
+ ```
106
+
107
+ ### className Pattern
108
+
109
+ Always accept and merge `className`:
110
+
111
+ ```tsx
112
+ import { cn } from "@/lib/utils"
113
+
114
+ interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
115
+ variant?: "default" | "outline"
116
+ }
117
+
118
+ export function Card({ className, variant = "default", ...props }: CardProps) {
119
+ return (
120
+ <div
121
+ className={cn(
122
+ "rounded-lg p-4",
123
+ variant === "outline" && "border",
124
+ className
125
+ )}
126
+ {...props}
127
+ />
128
+ )
129
+ }
130
+ ```
131
+
132
+ ## Data Fetching Patterns
133
+
134
+ ### Server Component (default)
135
+
136
+ Fetch data directly in Server Components:
137
+
138
+ ```tsx
139
+ export default async function Page() {
140
+ const data = await fetchData()
141
+ return <Component data={data} />
142
+ }
143
+ ```
144
+
145
+ ### Cached Data Function
146
+
147
+ Use `'use cache'` for reusable cached queries. `"use cache"` (and `cacheTag`/`cacheLife`/`updateTag`) requires the Cache Components opt-in flag — Next.js 16 does not enable it by default:
148
+
149
+ ```ts
150
+ // next.config.ts
151
+ const nextConfig = { cacheComponents: true }
152
+ ```
153
+
154
+ ```tsx
155
+ // data/products.ts
156
+ export async function getProducts() {
157
+ "use cache"
158
+ cacheTag("products")
159
+ cacheLife("hours")
160
+ return await db.products.findMany()
161
+ }
162
+ ```
163
+
164
+ ### Streaming to Client (React `use` hook)
165
+
166
+ Pass promises to Client Components for streaming:
167
+
168
+ ```tsx
169
+ // Server Component
170
+ export default function Page() {
171
+ const dataPromise = fetchData() // Don't await
172
+ return (
173
+ <Suspense fallback={<Loading />}>
174
+ <ClientDisplay dataPromise={dataPromise} />
175
+ </Suspense>
176
+ )
177
+ }
178
+
179
+ // Client Component
180
+ "use client"
181
+ import { use } from "react"
182
+
183
+ export function ClientDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
184
+ const data = use(dataPromise) // Suspends until resolved
185
+ return <Chart data={data} />
186
+ }
187
+ ```
188
+
189
+ ### Explicit Request-time with connection()
190
+
191
+ Use `connection()` to explicitly defer to request time without accessing runtime APIs:
192
+
193
+ ```tsx
194
+ import { connection } from "next/server"
195
+ import { Suspense } from "react"
196
+
197
+ async function UniqueContent() {
198
+ await connection() // Defer to request time
199
+ const uuid = crypto.randomUUID()
200
+ const timestamp = Date.now()
201
+ return <div>{uuid} - {timestamp}</div>
202
+ }
203
+
204
+ export default function Page() {
205
+ return (
206
+ <Suspense fallback={<Loading />}>
207
+ <UniqueContent />
208
+ </Suspense>
209
+ )
210
+ }
211
+ ```
212
+
213
+ **When to use `connection()`:**
214
+
215
+ | Scenario | Use connection()? |
216
+ |----------|-------------------|
217
+ | Need unique values per request | ✅ Yes |
218
+ | Using `Math.random()`, `Date.now()`, `crypto.randomUUID()` | ✅ Yes |
219
+ | Already using `cookies()` or `headers()` | ❌ No (not needed) |
220
+ | Data is cacheable | ❌ No (use `'use cache'`) |
221
+
222
+ ## Routing
223
+
224
+ ### Route Groups
225
+
226
+ Group routes without affecting URL:
227
+
228
+ ```
229
+ app/
230
+ ├── (protected)/ # Auth required - /dashboard, /settings
231
+ │ ├── dashboard/
232
+ │ ├── settings/
233
+ │ └── layout.tsx # Shared chrome (sidebar, auth check)
234
+ ├── (public)/ # Public - /login, /register, /about
235
+ │ ├── login/
236
+ │ ├── register/
237
+ │ └── about/
238
+ └── (marketing)/ # Marketing - /pricing, /features
239
+ ├── pricing/
240
+ └── features/
241
+ ```
242
+
243
+ ### Layout vs Template
244
+
245
+ | Aspect | layout.tsx | template.tsx |
246
+ |--------|------------|--------------|
247
+ | State | Persists across navigation | Resets on navigation |
248
+ | Effects | Run once | Run on every navigation |
249
+ | Use when | Shared chrome (nav, footer) | Analytics, animations that reset |
250
+
251
+ **Decision tree:**
252
+ ```
253
+ State/effects should reset on navigation?
254
+ ├── Yes → template.tsx
255
+ └── No → layout.tsx (default)
256
+ ```
257
+
258
+ ### Async Params (Next.js 16)
259
+
260
+ ```tsx
261
+ // Always await params and searchParams
262
+ export default async function Page({
263
+ params,
264
+ searchParams,
265
+ }: {
266
+ params: Promise<{ slug: string }>
267
+ searchParams: Promise<{ page?: string }>
268
+ }) {
269
+ const { slug } = await params
270
+ const { page = "1" } = await searchParams
271
+
272
+ const data = await fetchData(slug, parseInt(page))
273
+ return <Content data={data} />
274
+ }
275
+ ```
276
+
277
+ ## Suspense Strategy
278
+
279
+ ### When to Use Suspense
280
+
281
+ ```
282
+ Slow data fetch in Server Component?
283
+ ├── Yes → Wrap in <Suspense>
284
+ └── No → Direct render
285
+
286
+ Multiple independent slow sections?
287
+ ├── Yes → Separate <Suspense> boundaries
288
+ └── No → Single boundary or loading.tsx
289
+ ```
290
+
291
+ ### Patterns
292
+
293
+ **loading.tsx** - Entire route fallback:
294
+ ```tsx
295
+ // app/dashboard/loading.tsx
296
+ export default function Loading() {
297
+ return <DashboardSkeleton />
298
+ }
299
+ ```
300
+
301
+ **Suspense** - Granular streaming:
302
+ ```tsx
303
+ export default function Page() {
304
+ return (
305
+ <>
306
+ <Header /> {/* Renders immediately */}
307
+ <Suspense fallback={<StatsSkeleton />}>
308
+ <SlowStats /> {/* Streams when ready */}
309
+ </Suspense>
310
+ <Suspense fallback={<ChartSkeleton />}>
311
+ <SlowChart /> {/* Streams independently */}
312
+ </Suspense>
313
+ </>
314
+ )
315
+ }
316
+ ```
317
+
318
+ **Skeleton pattern** - Create a skeleton component for each loadable content:
319
+ ```tsx
320
+ // components/skeletons.tsx
321
+ export function CardSkeleton() {
322
+ return (
323
+ <div className="animate-pulse">
324
+ <div className="h-4 bg-muted rounded w-3/4 mb-2" />
325
+ <div className="h-4 bg-muted rounded w-1/2" />
326
+ </div>
327
+ )
328
+ }
329
+
330
+ export function TableSkeleton({ rows = 5 }: { rows?: number }) {
331
+ return (
332
+ <div className="space-y-2">
333
+ {Array.from({ length: rows }).map((_, i) => (
334
+ <div key={i} className="h-10 bg-muted rounded animate-pulse" />
335
+ ))}
336
+ </div>
337
+ )
338
+ }
339
+ ```
340
+
341
+ **Passing promises to client**:
342
+ ```tsx
343
+ // Server Component
344
+ export default function Page() {
345
+ const dataPromise = fetchData() // Start fetch, don't await
346
+ return <ClientChart dataPromise={dataPromise} />
347
+ }
348
+
349
+ // Client Component
350
+ "use client"
351
+ import { use } from "react"
352
+
353
+ export function ClientChart({ dataPromise }) {
354
+ const data = use(dataPromise) // Suspends until resolved
355
+ return <Chart data={data} />
356
+ }
357
+ ```
358
+
359
+ ## State Management
360
+
361
+ ### useTransition Pattern
362
+
363
+ Wrap non-urgent UI updates to keep interactions smooth:
364
+
365
+ ```tsx
366
+ "use client"
367
+ import { useTransition } from "react"
368
+
369
+ function SubmitButton({ action }: { action: () => Promise<void> }) {
370
+ const [isPending, startTransition] = useTransition()
371
+
372
+ return (
373
+ <button
374
+ onClick={() => startTransition(() => action())}
375
+ disabled={isPending}
376
+ >
377
+ {isPending ? "Saving..." : "Save"}
378
+ </button>
379
+ )
380
+ }
381
+ ```
382
+
383
+ **Guidelines:**
384
+ - Use `isPending` for feedback (disable buttons, show spinners)
385
+ - Don't wrap controlled input state in transitions
386
+ - After `await` inside transition, wrap subsequent `setState` in another `startTransition`
387
+
388
+ ## Data Patterns
389
+
390
+ ### "use cache" (Next.js 16)
391
+
392
+ Function-level caching:
393
+
394
+ ```tsx
395
+ "use cache"
396
+
397
+ export async function getProducts() {
398
+ const products = await db.query.products.findMany()
399
+ return products
400
+ }
401
+
402
+ // With cache tags
403
+ import { cacheTag } from "next/cache"
404
+
405
+ export async function getProduct(id: string) {
406
+ "use cache"
407
+ cacheTag(`product-${id}`)
408
+ return db.query.products.findFirst({ where: eq(products.id, id) })
409
+ }
410
+ ```
411
+
412
+ ### Server Actions
413
+
414
+ ```tsx
415
+ "use server"
416
+
417
+ import { updateTag, revalidateTag } from "next/cache"
418
+ import { z } from "zod"
419
+
420
+ const schema = z.object({
421
+ title: z.string().min(1),
422
+ content: z.string(),
423
+ })
424
+
425
+ export async function createPost(formData: FormData) {
426
+ const parsed = schema.parse({
427
+ title: formData.get("title"),
428
+ content: formData.get("content"),
429
+ })
430
+
431
+ await db.insert(posts).values(parsed)
432
+
433
+ // Read-your-writes (immediate)
434
+ updateTag("posts")
435
+
436
+ // Or SWR-style revalidation
437
+ // revalidateTag("posts", "max")
438
+ }
439
+
440
+ // Refresh uncached data
441
+ import { refresh } from "next/cache"
442
+
443
+ export async function updateProfile(data: FormData) {
444
+ await db.update(...)
445
+ refresh() // Triggers client router refresh
446
+ }
447
+ ```
448
+
449
+ ### Proxy API (Next.js 16)
450
+
451
+ Replaces middleware for request interception. Place at project root (same level as `app/`):
452
+
453
+ ```tsx
454
+ // proxy.ts (project root)
455
+ import { NextResponse } from "next/server"
456
+ import type { NextRequest } from "next/server"
457
+
458
+ export async function proxy(request: NextRequest) {
459
+ const session = request.cookies.get("session")
460
+
461
+ if (!session && request.nextUrl.pathname.startsWith("/dashboard")) {
462
+ return NextResponse.redirect(new URL("/login", request.url))
463
+ }
464
+
465
+ return NextResponse.next()
466
+ }
467
+
468
+ export const config = {
469
+ matcher: ['/dashboard/:path*', '/api/:path*'],
470
+ }
471
+ ```
472
+
473
+ ### Request APIs
474
+
475
+ All request APIs are async in Next.js 16:
476
+
477
+ ```tsx
478
+ import { cookies, headers, draftMode } from "next/headers"
479
+
480
+ export default async function Page() {
481
+ const cookieStore = await cookies()
482
+ const headersList = await headers()
483
+ const { isEnabled } = await draftMode()
484
+ }
485
+ ```
486
+
487
+ ## Error Handling
488
+
489
+ Define only when custom UX needed:
490
+
491
+ ```
492
+ app/
493
+ ├── error.tsx # Route-level errors
494
+ ├── global-error.tsx # Root layout errors
495
+ ├── not-found.tsx # 404 pages
496
+ └── loading.tsx # Loading states
497
+ ```
498
+
499
+ Otherwise inherit from parent segment.
@@ -0,0 +1,127 @@
1
+ # Project Setup
2
+
3
+ ## Create New Project
4
+
5
+ ### Minimal Setup
6
+
7
+ Use the CLI to scaffold a Next.js project directly:
8
+
9
+ ```bash
10
+ bunx --bun shadcn@latest init --template next --base base
11
+ ```
12
+
13
+ `--base` picks the primitive library: `base` (Base UI, default), `radix`, or
14
+ `aria` (React Aria). Component APIs differ per base — see
15
+ [shadcn-platform.md](shadcn-platform.md). Add `--rtl` if the app needs
16
+ right-to-left support.
17
+
18
+ ### With Preset Code
19
+
20
+ ```bash
21
+ bunx --bun shadcn@latest init --preset <CODE> --template next
22
+ ```
23
+
24
+ Preset codes are short opaque strings from [ui.shadcn.com/create](https://ui.shadcn.com/create) — pass them through verbatim rather than expanding them into individual flags. Prefer this when you want a specific visual system without hardcoding individual style, font, or icon choices into the skill:
25
+
26
+ ```bash
27
+ bunx --bun shadcn@latest init --preset b4h07r5A1 --template next
28
+ ```
29
+
30
+ `shadcn preset decode <code>` prints what a code contains (style, base color,
31
+ theme, font, icon library, radius) if you need to read it before applying.
32
+
33
+ For a project that already exists, apply a preset instead of re-running `init`:
34
+
35
+ ```bash
36
+ bunx --bun shadcn@latest apply <CODE> # theme, fonts, components
37
+ bunx --bun shadcn@latest apply <CODE> --only theme # just the theme
38
+ ```
39
+
40
+ ### Monorepo
41
+
42
+ ```bash
43
+ bunx --bun shadcn@latest init \
44
+ --template next \
45
+ --monorepo
46
+ ```
47
+
48
+ ### Existing Project
49
+
50
+ If the Next.js app already exists, run the initializer from the project root:
51
+
52
+ ```bash
53
+ bunx --bun shadcn@latest init
54
+ ```
55
+
56
+ ### Inspect Before Changing
57
+
58
+ Use the CLI to inspect project state or preview registry changes before writing files:
59
+
60
+ ```bash
61
+ bunx --bun shadcn@latest info
62
+ bunx --bun shadcn@latest add button --dry-run
63
+ bunx --bun shadcn@latest docs button
64
+ ```
65
+
66
+ ## Add Components
67
+
68
+ ```bash
69
+ # Single component
70
+ bunx --bun shadcn@latest add button
71
+
72
+ # Multiple components
73
+ bunx --bun shadcn@latest add button card input
74
+
75
+ # All components
76
+ bunx --bun shadcn@latest add --all
77
+ ```
78
+
79
+ ## Common Dependencies
80
+
81
+ ```bash
82
+ # Forms
83
+ bun add react-hook-form @hookform/resolvers zod
84
+
85
+ # AI
86
+ bun add ai @ai-sdk/anthropic
87
+
88
+ # Animation
89
+ bun add motion # For Motion
90
+ bun add gsap @gsap/react # For GSAP
91
+
92
+ # Icons (pick one)
93
+ bun add lucide-react # Default
94
+ ```
95
+
96
+ ## Project Structure After Setup
97
+
98
+ ```
99
+ project/
100
+ ├── app/
101
+ │ ├── globals.css # Theme tokens
102
+ │ ├── layout.tsx # Root layout
103
+ │ └── page.tsx # Home page
104
+ ├── components/
105
+ │ └── ui/ # shadcn components
106
+ ├── lib/
107
+ │ └── utils.ts # cn() helper
108
+ ├── public/
109
+ ├── components.json # shadcn config
110
+ ├── tsconfig.json
111
+ └── package.json
112
+ ```
113
+
114
+ ## Bun Commands Reference
115
+
116
+ | Task | Command |
117
+ |------|---------|
118
+ | Install deps | `bun install` |
119
+ | Add package | `bun add package` |
120
+ | Dev server | `bun --bun next dev` |
121
+ | Build | `bun --bun next build` |
122
+ | Start prod | `bun --bun next start` |
123
+ | Add shadcn component | `bunx --bun shadcn@latest add component` |
124
+ | Create project | `bunx --bun shadcn@latest init --template next --base base` |
125
+ | Read project config | `bunx --bun shadcn@latest info --json` |
126
+ | Component API docs | `bunx --bun shadcn@latest docs component` |
127
+