@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,258 @@
1
+ # shadcn Platform
2
+
3
+ The parts of shadcn that are not individual components: which primitive base to
4
+ build on, the CLI verbs worth knowing, and the CSS-level systems (typeset,
5
+ shimmer, scroll-fade).
6
+
7
+ ## Choosing a base (do this first)
8
+
9
+ shadcn components ship on three primitive libraries: Base UI, Radix, and React
10
+ Aria. **Base UI is the default.** The choice is per-project and set at `init` —
11
+ components installed later inherit it.
12
+
13
+ ```bash
14
+ bunx --bun shadcn@latest init --template next --base base # Base UI (default)
15
+ bunx --bun shadcn@latest init --template next --base radix # Radix (legacy projects)
16
+ bunx --bun shadcn@latest init --template next --base aria # React Aria
17
+ ```
18
+
19
+ | Base | Pick it when |
20
+ |------|-------------|
21
+ | `base` | New projects. Default since July 2026, most actively developed, gets new components first. |
22
+ | `radix` | Existing codebase already on Radix, or a dependency expects Radix primitives. |
23
+ | `aria` | Accessibility/interaction requirements beyond the defaults — React Aria's behavior hooks. |
24
+
25
+ **Why this matters for generated code:** the same component name has different
26
+ props and sub-components per base. Docs are base-scoped too —
27
+ `ui.shadcn.com/docs/components/base/sidebar` vs `.../radix/sidebar`. Never write
28
+ component code from memory without knowing the project's base.
29
+
30
+ The difference that bites most often: **Base UI composes through a `render`
31
+ prop, Radix through `asChild`.**
32
+
33
+ ```tsx
34
+ // Base UI (default) — element goes in render, children stay as children
35
+ <SidebarMenuButton render={<Link href="/inbox" />}>
36
+ <Inbox />
37
+ <span>Inbox</span>
38
+ </SidebarMenuButton>
39
+
40
+ // Radix — element wraps the children
41
+ <SidebarMenuButton asChild>
42
+ <Link href="/inbox">
43
+ <Inbox />
44
+ <span>Inbox</span>
45
+ </Link>
46
+ </SidebarMenuButton>
47
+ ```
48
+
49
+ Read the base from `components.json` (or `shadcn info --json`) before editing an
50
+ existing project.
51
+
52
+ `migrate radix` does **not** switch a project from Radix to Base UI — it rewrites
53
+ `@radix-ui/react-*` imports to the single `radix-ui` package. Radix → Base UI is
54
+ a component-at-a-time migration driven by the official shadcn skill:
55
+
56
+ ```bash
57
+ bunx --bun skills add shadcn/ui
58
+ # then ask the agent: "migrate accordion to base-ui"
59
+ ```
60
+
61
+ Both libraries stay installed while you work, each component lands in its own
62
+ commit, and every run writes a report to `.migration/<component>.md`.
63
+
64
+ ## CLI verbs beyond `add`
65
+
66
+ `add` and `init` are the familiar ones. These four are what make the CLI useful
67
+ to an agent:
68
+
69
+ ```bash
70
+ shadcn info --json # project config: framework, base, tailwind, aliases, installed components
71
+ shadcn docs button # API reference for a component, resolved to THIS project's base
72
+ shadcn docs button --json # machine-readable, for piping into context
73
+ shadcn view button card # inspect registry item source before installing
74
+ shadcn search @shadcn -q chart # search a registry namespace
75
+ ```
76
+
77
+ **Prefer `shadcn docs <component>` over recalling props from memory or fetching
78
+ `llms.txt`** — it resolves against the project's actual base and version. Use
79
+ `shadcn view` before `add` when you are unsure what a registry item pulls in.
80
+
81
+ Other verbs: `add <component> --diff` (upstream changes to an installed
82
+ component — the standalone `diff` command is deprecated), `apply <preset>`
83
+ (apply a preset to an existing project; `--only theme,font` for just those
84
+ parts), `preset decode|resolve|url|open` (inspect a preset code), `build`
85
+ (generate registry JSON), `migrate` (`icons`, `rtl`, `radix`), `eject` (inline
86
+ `shadcn/tailwind.css` and drop the `shadcn` dependency).
87
+
88
+ ### `migrate icons`
89
+
90
+ Swapping icon libraries across a whole project is a single command:
91
+
92
+ ```bash
93
+ bunx --bun shadcn@latest migrate icons --from lucide --to phosphor
94
+ ```
95
+
96
+ ## The official shadcn skill
97
+
98
+ shadcn publishes its own agent skill, which injects live project config
99
+ (`shadcn info --json`) plus the full CLI and registry reference:
100
+
101
+ ```bash
102
+ bunx --bun skills add shadcn/ui
103
+ ```
104
+
105
+ It activates when the project has a `components.json`. It covers CLI mechanics
106
+ and registry authoring — **this skill covers project conventions, architecture,
107
+ and Next.js integration instead.** Install both; don't duplicate CLI reference
108
+ material here.
109
+
110
+ There is also an MCP server for registry search and install from within the
111
+ editor — wire it into Claude Code with
112
+ `bunx --bun shadcn@latest mcp init --client claude`.
113
+
114
+ ## Typeset — styling rendered markdown
115
+
116
+ One CSS file you own that styles headings, paragraphs, lists, tables and code
117
+ inside a wrapper class. Replaces hand-written `prose`-style overrides and
118
+ per-context markdown CSS.
119
+
120
+ **Use it for:** chat message bodies, docs pages, blog posts, LLM-streamed
121
+ markdown — anywhere you render HTML you did not author.
122
+
123
+ Typeset is **not** part of `init` and has no `add` command. Generate the file in
124
+ the builder at [ui.shadcn.com/typeset](https://ui.shadcn.com/typeset), drop it
125
+ next to your main CSS, and import it after Tailwind:
126
+
127
+ ```css
128
+ /* app/globals.css */
129
+ @import "tailwindcss";
130
+ @import "./typeset.css";
131
+ ```
132
+
133
+ Three variables drive the whole rhythm; everything else derives from them:
134
+
135
+ ```css
136
+ .typeset {
137
+ --typeset-font-body: inherit;
138
+ --typeset-font-heading: var(--font-heading);
139
+ --typeset-font-mono: var(--font-mono);
140
+ --typeset-size: 1em; /* base text size */
141
+ --typeset-leading: 1.75; /* line-height */
142
+ --typeset-flow: 1.25em; /* space between blocks */
143
+ }
144
+ ```
145
+
146
+ Define one preset per context and apply both classes:
147
+
148
+ ```css
149
+ .typeset-docs {
150
+ --typeset-size: 15px;
151
+ --typeset-leading: 1.75;
152
+ --typeset-flow: 1.25em;
153
+ }
154
+
155
+ .typeset-chat {
156
+ --typeset-leading: 1.6;
157
+ --typeset-flow: 1em; /* tighter — chat bubbles are short */
158
+ }
159
+ ```
160
+
161
+ ```tsx
162
+ <div className="typeset typeset-chat">
163
+ <Response>{message}</Response>
164
+ </div>
165
+ ```
166
+
167
+ It is container-aware (sizes to its container, not just the viewport) and
168
+ **streaming-stable**: appending a new block does not restyle blocks already
169
+ rendered above it. That property is the reason to prefer it over ad-hoc CSS in
170
+ streaming chat UIs.
171
+
172
+ ## Shimmer — loading and processing text
173
+
174
+ CSS-only animated sweep across text. No component, no JS.
175
+
176
+ ```tsx
177
+ <p className="shimmer text-muted-foreground">Generating response…</p>
178
+ ```
179
+
180
+ | Class | Effect |
181
+ |-------|--------|
182
+ | `shimmer-color-<color>` | Highlight color, e.g. `shimmer-color-blue-500/60` |
183
+ | `shimmer-duration-<ms>` | Sweep speed (default 2000) |
184
+ | `shimmer-spread-<n>` | Width of the highlight band |
185
+ | `shimmer-angle-<deg>` | Tilt (default 20) |
186
+ | `shimmer-once` | Single sweep instead of looping |
187
+ | `shimmer-reverse` | Reverse direction |
188
+
189
+ Adapts to the element's text color, brightens in dark mode, respects
190
+ `prefers-reduced-motion` and RTL automatically.
191
+
192
+ **Use shimmer for indeterminate text states** ("Thinking…", "Searching…") and
193
+ `Skeleton` for layout placeholders with known shape. Don't stack both.
194
+
195
+ ## Scroll-fade — soft scroll container edges
196
+
197
+ Masks the content itself at the edges of a scroll container rather than
198
+ overlaying a gradient, so it works on any background.
199
+
200
+ ```tsx
201
+ <div className="scroll-fade overflow-y-auto">{/* content */}</div>
202
+ ```
203
+
204
+ | Class | Effect |
205
+ |-------|--------|
206
+ | `scroll-fade` / `scroll-fade-y` | Vertical |
207
+ | `scroll-fade-x` | Horizontal |
208
+ | `scroll-fade-t` / `-b` / `-l` / `-r` | Single edge |
209
+ | `scroll-fade-s` / `-e` | Start/end edge (RTL-aware) |
210
+ | `scroll-fade-<n>` | Fade depth on the spacing scale |
211
+ | `scroll-fade-none` | Disable |
212
+
213
+ Scroll-aware: the top edge stays crisp until you scroll away from it.
214
+
215
+ Both `shimmer` and `scroll-fade` come from `shadcn/tailwind.css`, which `init`
216
+ wires up. In a project that skipped it:
217
+
218
+ ```css
219
+ @import "tailwindcss";
220
+ @import "shadcn/tailwind.css";
221
+ ```
222
+
223
+ ## RTL support
224
+
225
+ Sidebar and the CSS utilities are RTL-aware. Opt in at init with `--rtl`,
226
+ retrofit an existing project with `migrate rtl`, and pass `dir` on the `Sidebar`
227
+ component. Prefer logical utilities (`ms-`/`me-`, `scroll-fade-s/-e`)
228
+ over physical ones (`ml-`/`mr-`) in any project that might need it.
229
+
230
+ ## Package imports (alias alternative)
231
+
232
+ Projects may use Node package imports instead of `tsconfig.json` paths:
233
+
234
+ ```json
235
+ // package.json
236
+ { "imports": { "#components/*": "./src/components/*.tsx", "#lib/*": "./src/lib/*.ts" } }
237
+ ```
238
+
239
+ ```tsx
240
+ import { Button } from "#components/ui/button";
241
+ import { cn } from "#lib/utils";
242
+ ```
243
+
244
+ Requires `moduleResolution: "bundler"` and `resolvePackageJsonImports: true`, and
245
+ the matching `aliases` block in `components.json`. The CLI rewrites imports to
246
+ whichever alias style is configured.
247
+
248
+ **Default to `@/` for new projects.** In an existing project, read
249
+ `components.json` and follow what is already there — never mix both styles.
250
+
251
+ ## Registries
252
+
253
+ Beyond `@shadcn`, the CLI resolves namespaced registries (`@acme/button`),
254
+ including private and GitHub-hosted ones. If you author a registry with more
255
+ than a few hundred items, implement
256
+ [dynamic search](https://ui.shadcn.com/docs/registry/dynamic-search) so
257
+ `shadcn search` filters server-side instead of downloading the whole catalog.
258
+ Not needed for consuming registries.
@@ -0,0 +1,274 @@
1
+ # Sidebar
2
+
3
+ shadcn/ui sidebar with nested layouts for dashboard applications.
4
+
5
+ ## Start from a block, not from scratch
6
+
7
+ Before hand-writing an `AppSidebar`, check whether a block already matches the
8
+ shape you need. A block installs a complete, working sidebar you then edit —
9
+ faster and less error-prone than assembling sub-components by hand.
10
+
11
+ ```bash
12
+ bunx --bun shadcn@latest add sidebar-07
13
+ ```
14
+
15
+ | Block | Shape |
16
+ |-------|-------|
17
+ | `sidebar-01` | Navigation grouped by section (simplest) |
18
+ | `sidebar-02` | Collapsible sections |
19
+ | `sidebar-03` | Submenus |
20
+ | `sidebar-04` | Floating sidebar with submenus |
21
+ | `sidebar-05` | Collapsible submenus |
22
+ | `sidebar-06` | Submenus as dropdowns |
23
+ | `sidebar-07` | Collapses to icons — the common dashboard default |
24
+ | `sidebar-08` | Inset sidebar with secondary navigation |
25
+ | `sidebar-09` | Collapsible nested sidebars |
26
+ | `sidebar-10` | Sidebar in a popover |
27
+ | `sidebar-11` | Collapsible file tree |
28
+ | `sidebar-12` | Sidebar with a calendar |
29
+ | `sidebar-13` | Sidebar in a dialog |
30
+ | `sidebar-14` | Sidebar on the right |
31
+ | `sidebar-15` | Left and right sidebar |
32
+ | `sidebar-16` | Sticky site header |
33
+
34
+ Preview them at [ui.shadcn.com/blocks/sidebar](https://ui.shadcn.com/blocks/sidebar).
35
+ Use `shadcn view sidebar-07` to read the source before installing.
36
+
37
+ The patterns below are for when no block fits, or when adapting one.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ bunx --bun shadcn@latest add sidebar
43
+ ```
44
+
45
+ The sidebar API differs between Base UI, Radix and React Aria. Check the
46
+ project's base (`shadcn info --json`) and read
47
+ `shadcn docs sidebar` rather than assuming — the examples below target Base UI,
48
+ the current default. The difference that shows up in every example: Base UI
49
+ composes through a `render` prop (`<SidebarMenuButton render={<Link href="/" />}>`
50
+ with the icon and label as children), where Radix wraps the children in `asChild`.
51
+
52
+ ## Layout Pattern
53
+
54
+ Use nested layouts with SidebarProvider for persistent sidebar state:
55
+
56
+ ```
57
+ app/
58
+ ├── (dashboard)/ # Route group for sidebar pages
59
+ │ ├── layout.tsx # SidebarProvider + AppSidebar
60
+ │ ├── page.tsx # Dashboard home
61
+ │ ├── settings/
62
+ │ │ └── page.tsx
63
+ │ └── components/ # Route-specific components
64
+ ├── (public)/ # Public routes (no sidebar)
65
+ │ └── login/
66
+ └── layout.tsx # Root layout
67
+ ```
68
+
69
+ ### Dashboard Layout
70
+
71
+ ```tsx
72
+ // app/(dashboard)/layout.tsx
73
+ import { AppSidebar } from "@/components/layout/app-sidebar"
74
+ import {
75
+ SidebarInset,
76
+ SidebarProvider,
77
+ } from "@/components/ui/sidebar"
78
+
79
+ export default function DashboardLayout({
80
+ children,
81
+ }: {
82
+ children: React.ReactNode
83
+ }) {
84
+ return (
85
+ <SidebarProvider>
86
+ <AppSidebar />
87
+ <SidebarInset>{children}</SidebarInset>
88
+ </SidebarProvider>
89
+ )
90
+ }
91
+ ```
92
+
93
+ ### Page Component
94
+
95
+ Keep pages clean - content only, no layout chrome:
96
+
97
+ ```tsx
98
+ // app/(dashboard)/page.tsx
99
+ import { DocumentWorkspace } from "@/components/workspace/document-workspace"
100
+ import { Suspense } from "react"
101
+
102
+ export default function DashboardPage() {
103
+ return (
104
+ <Suspense fallback={<DashboardSkeleton />}>
105
+ <DocumentWorkspace />
106
+ </Suspense>
107
+ )
108
+ }
109
+ ```
110
+
111
+ ## AppSidebar Component
112
+
113
+ ```tsx
114
+ // components/layout/app-sidebar.tsx
115
+ import Link from "next/link"
116
+ import {
117
+ Sidebar,
118
+ SidebarContent,
119
+ SidebarFooter,
120
+ SidebarGroup,
121
+ SidebarGroupContent,
122
+ SidebarGroupLabel,
123
+ SidebarHeader,
124
+ SidebarMenu,
125
+ SidebarMenuButton,
126
+ SidebarMenuItem,
127
+ SidebarRail,
128
+ SidebarSeparator,
129
+ } from "@/components/ui/sidebar"
130
+ import { NAV_GROUPS, FOOTER_NAV_ITEMS } from "./nav"
131
+
132
+ export function AppSidebar() {
133
+ return (
134
+ <Sidebar variant="inset" collapsible="icon">
135
+ <SidebarHeader>
136
+ <SidebarMenu>
137
+ <SidebarMenuItem>
138
+ <SidebarMenuButton
139
+ size="lg"
140
+ render={<Link href="/" className="flex items-center gap-3" />}
141
+ >
142
+ <Logo className="size-8" />
143
+ <span className="text-base font-semibold">App Name</span>
144
+ </SidebarMenuButton>
145
+ </SidebarMenuItem>
146
+ </SidebarMenu>
147
+ </SidebarHeader>
148
+
149
+ <SidebarContent>
150
+ {NAV_GROUPS.map((group, index) => (
151
+ <div key={group.title}>
152
+ <SidebarGroup>
153
+ <SidebarGroupLabel>{group.title}</SidebarGroupLabel>
154
+ <SidebarGroupContent>
155
+ <SidebarMenu>
156
+ {group.items.map((item) => (
157
+ <SidebarMenuItem key={item.title}>
158
+ <SidebarMenuButton render={<Link href={item.href} />}>
159
+ <item.icon />
160
+ <span>{item.title}</span>
161
+ </SidebarMenuButton>
162
+ </SidebarMenuItem>
163
+ ))}
164
+ </SidebarMenu>
165
+ </SidebarGroupContent>
166
+ </SidebarGroup>
167
+ {index < NAV_GROUPS.length - 1 && <SidebarSeparator />}
168
+ </div>
169
+ ))}
170
+ </SidebarContent>
171
+
172
+ <SidebarFooter>
173
+ <SidebarSeparator />
174
+ <SidebarMenu>
175
+ {FOOTER_NAV_ITEMS.map((item) => (
176
+ <SidebarMenuItem key={item.title}>
177
+ <SidebarMenuButton render={<Link href={item.href} />}>
178
+ <item.icon />
179
+ <span>{item.title}</span>
180
+ </SidebarMenuButton>
181
+ </SidebarMenuItem>
182
+ ))}
183
+ </SidebarMenu>
184
+ </SidebarFooter>
185
+
186
+ <SidebarRail />
187
+ </Sidebar>
188
+ )
189
+ }
190
+ ```
191
+
192
+ ## Navigation Config
193
+
194
+ Separate navigation data from component:
195
+
196
+ ```tsx
197
+ // components/layout/nav.ts
198
+ import { Home, Settings, Users, HelpCircle } from "lucide-react"
199
+ import type { LucideIcon } from "lucide-react"
200
+
201
+ interface NavItem {
202
+ title: string
203
+ href: string
204
+ icon: LucideIcon
205
+ }
206
+
207
+ interface NavGroup {
208
+ title: string
209
+ items: NavItem[]
210
+ }
211
+
212
+ export const NAV_GROUPS: NavGroup[] = [
213
+ {
214
+ title: "Main",
215
+ items: [
216
+ { title: "Dashboard", href: "/", icon: Home },
217
+ { title: "Users", href: "/users", icon: Users },
218
+ ],
219
+ },
220
+ ]
221
+
222
+ export const FOOTER_NAV_ITEMS: NavItem[] = [
223
+ { title: "Settings", href: "/settings", icon: Settings },
224
+ { title: "Help", href: "/help", icon: HelpCircle },
225
+ ]
226
+ ```
227
+
228
+ ## Sidebar Variants
229
+
230
+ | Variant | Description |
231
+ |---------|-------------|
232
+ | `sidebar` | Standard sidebar (default) |
233
+ | `inset` | Sidebar with padding, content area has rounded corners |
234
+ | `floating` | Sidebar floats over content |
235
+
236
+ ```tsx
237
+ <Sidebar variant="inset" collapsible="icon">
238
+ ```
239
+
240
+ ## Collapsible Options
241
+
242
+ | Option | Behavior |
243
+ |--------|----------|
244
+ | `icon` | Collapses to icon-only rail |
245
+ | `offcanvas` | Slides completely off-screen |
246
+ | `none` | Not collapsible |
247
+
248
+ ## RTL
249
+
250
+ `Sidebar` takes a `dir` prop and positions via `data-side` attributes, so
251
+ right-to-left layouts work without JS conditionals — `SidebarTrigger` flips its
252
+ icon automatically. Opt in project-wide at `init` with `--rtl`, or retrofit with
253
+ `shadcn migrate rtl`. In any project that might need RTL, use logical utilities
254
+ (`ms-`/`me-`, `ps-`/`pe-`) instead of `ml-`/`mr-` in sidebar markup.
255
+
256
+ ## Persisting open state
257
+
258
+ `SidebarProvider` takes `defaultOpen` (uncontrolled) or `open` / `onOpenChange`
259
+ (controlled); width comes from the `--sidebar-width` CSS variable. To keep the
260
+ sidebar's state across reloads without a hydration mismatch, read a cookie in the
261
+ layout Server Component and pass it to `defaultOpen` — don't read it client-side
262
+ in an effect.
263
+
264
+ For custom triggers, `useSidebar()` exposes `toggleSidebar`, `isMobile`, and the
265
+ mobile-specific `openMobile` / `setOpenMobile`.
266
+
267
+ ## File Structure
268
+
269
+ ```
270
+ components/
271
+ └── layout/
272
+ ├── app-sidebar.tsx # Sidebar component
273
+ └── nav.ts # Navigation config
274
+ ```