@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,555 @@
1
+ # Styling
2
+
3
+ ## Theme System
4
+
5
+ ### globals.css Structure
6
+
7
+ shadcn generates base variables automatically based on your chosen preset. Customize for your project:
8
+
9
+ ```css
10
+ @import "tailwindcss";
11
+
12
+ /* Note: Tailwind v3 projects use @tailwind base; @tailwind components; @tailwind utilities; instead */
13
+
14
+ /* :root and .dark live OUTSIDE @layer base and hold full color values (OKLCH preferred) */
15
+ :root {
16
+ /* shadcn base variables come from preset */
17
+ --background: ...;
18
+ --foreground: ...;
19
+ --primary: ...;
20
+ --secondary: ...;
21
+ /* etc. */
22
+
23
+ /* Add your own variables as needed */
24
+ --brand: oklch(0.55 0.2 260);
25
+ }
26
+
27
+ .dark {
28
+ --brand: oklch(0.7 0.18 260);
29
+ }
30
+
31
+ @theme inline {
32
+ --color-brand: var(--brand);
33
+ }
34
+ ```
35
+
36
+ The `@theme inline` mapping is what makes the `bg-brand` / `text-brand` utilities work — a variable without it generates no utility.
37
+
38
+ **Choose preset**: Use [ui.shadcn.com/create](https://ui.shadcn.com/create) to select named style (vega, nova, maia, lyra, mira, luma, sera, rhea), base color, font, icon library, and radius. The customizer outputs a single preset code that encodes all choices.
39
+
40
+ ### Theme Customization
41
+
42
+ Quick customizations in `globals.css`:
43
+
44
+ ```css
45
+ :root {
46
+ /* Typography - change fonts */
47
+ --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
48
+ --font-serif: Georgia, serif;
49
+ --font-mono: "Fira Code", ui-monospace, monospace;
50
+
51
+ /* Border radius - affects all rounded corners */
52
+ --radius: 0.5rem; /* Default */
53
+ /* --radius: 0.25rem; /* Sharp */
54
+ /* --radius: 0.75rem; /* More rounded */
55
+ /* --radius: 1rem; /* Very rounded */
56
+ /* --radius: 1.3rem; /* Pill-like buttons */
57
+ }
58
+ ```
59
+
60
+ | Variable | Effect |
61
+ |----------|--------|
62
+ | `--font-sans` | Body text, buttons, inputs |
63
+ | `--font-mono` | Code blocks, technical content |
64
+ | `--radius` | All rounded corners (buttons, cards, inputs) |
65
+
66
+ **Tip**: Larger `--radius` values (1rem+) give a softer, more modern look. Smaller values (0.25rem) feel sharper and technical.
67
+
68
+ ### Using Theme Colors
69
+
70
+ ```tsx
71
+ // ✅ Use CSS variables
72
+ <div className="bg-primary text-primary-foreground" />
73
+ <div className="border-border" />
74
+ <div className="text-muted-foreground" />
75
+
76
+ // ❌ Never hardcode colors
77
+ <div className="bg-blue-500" />
78
+ <div className="text-[#1a1a1a]" />
79
+ ```
80
+
81
+ ## shadcn/ui Presets
82
+
83
+ Available styles at ui.shadcn.com/create:
84
+
85
+ | Preset | Character |
86
+ |--------|-----------|
87
+ | vega | Classic shadcn/ui look. Clean, neutral, familiar |
88
+ | nova | Reduced padding and margins for compact layouts |
89
+ | maia | Soft and rounded, with generous spacing |
90
+ | lyra | Boxy and sharp. Pairs well with mono fonts |
91
+ | mira | Compact. Made for dense interfaces |
92
+ | luma | Newer official style — see ui.shadcn.com/create |
93
+ | sera | Newer official style — see ui.shadcn.com/create |
94
+ | rhea | A more compact Luma. Tighter spacing, smaller controls, denser surfaces — built for focused product interfaces |
95
+
96
+ ### Fonts
97
+
98
+ Body/mono fonts the preset builder offers (these ids are what the preset code
99
+ encodes — `shadcn preset decode <code>` prints them back):
100
+
101
+ | Font | Type | Character |
102
+ |------|------|-----------|
103
+ | geist | Sans | Vercel's modern geometric sans |
104
+ | inter | Sans | Clean, versatile (classic default) |
105
+ | figtree | Sans | Friendly, geometric |
106
+ | dm-sans | Sans | Compact geometric with character |
107
+ | outfit | Sans | Modern, soft |
108
+ | noto-sans | Sans | Universal language support |
109
+ | nunito-sans | Sans | Rounded, approachable |
110
+ | roboto | Sans | Google's versatile sans |
111
+ | raleway | Sans | Elegant, thin-weight display |
112
+ | public-sans | Sans | US government standard, neutral |
113
+ | jetbrains-mono | Mono | Developer-focused monospace |
114
+ | geist-mono | Mono | Vercel's monospace |
115
+
116
+ Heading fonts (`fontHeading`) are a separate, longer list — lora, merriweather,
117
+ playfair-display, noto-serif, roboto-slab, oxanium, manrope, space-grotesk,
118
+ montserrat, ibm-plex-sans, source-sans-3, instrument-sans, eb-garamond,
119
+ instrument-serif. It defaults to `inherit` (same face as the body).
120
+
121
+ ## Icon Libraries
122
+
123
+ Priority order (use first available). The names below are the CLI's library ids —
124
+ pass them verbatim to `shadcn migrate icons --from <id> --to <id>`:
125
+
126
+ 1. **lucide** (default) - `bun add lucide-react`
127
+ 2. **tabler** - `bun add @tabler/icons-react`
128
+ 3. **hugeicons** - `bun add @hugeicons/react @hugeicons/core-free-icons` (the old `hugeicons-react` package is deprecated)
129
+ 4. **phosphor** - `bun add @phosphor-icons/react`
130
+ 5. **remixicon** - `bun add @remixicon/react`
131
+
132
+ ```tsx
133
+ // lucide example
134
+ import { ChevronRight, Menu, X } from "lucide-react"
135
+
136
+ <Button>
137
+ Next <ChevronRight data-icon="inline-end" />
138
+ </Button>
139
+ ```
140
+
141
+ ## Animations
142
+
143
+ ### CSS Page Transitions
144
+
145
+ Add to `globals.css`:
146
+
147
+ ```css
148
+ @keyframes page-in {
149
+ from {
150
+ opacity: 0;
151
+ transform: translateY(8px);
152
+ }
153
+ to {
154
+ opacity: 1;
155
+ transform: translateY(0);
156
+ }
157
+ }
158
+
159
+ @layer utilities {
160
+ .animate-page-in {
161
+ animation: page-in 0.6s ease-out both;
162
+ }
163
+ }
164
+ ```
165
+
166
+ Usage in layout or template:
167
+
168
+ ```tsx
169
+ // template.tsx - animates on every navigation
170
+ export default function Template({ children }: { children: React.ReactNode }) {
171
+ return <main className="animate-page-in">{children}</main>
172
+ }
173
+ ```
174
+
175
+ ### View Transitions API
176
+
177
+ No config needed. View transitions work in the App Router out of the box — it
178
+ runs React canary releases, which ship `ViewTransition`. The old
179
+ `experimental.viewTransition` flag is gone from Next.js 16's config type; adding
180
+ it now is a type error, not a no-op.
181
+
182
+ Wrap what should animate in React's `<ViewTransition>` — no extra install.
183
+ Without browser support it degrades gracefully: no animation, app still works.
184
+
185
+ ```tsx
186
+ import { ViewTransition } from "react"
187
+ ```
188
+
189
+ `<ViewTransition>` animations fire on Transitions, `<Suspense>`, and
190
+ `useDeferredValue`. Route navigations are Transitions, so they activate
191
+ automatically on navigation; plain `setState` does not trigger them.
192
+
193
+ | Pattern | Communicates | Key API |
194
+ |---------|--------------|---------|
195
+ | Shared-element morph | "Same thing, going deeper" | Same `name` on both elements |
196
+ | Suspense reveal | "Data loaded" | `enter`/`exit` on fallback + content, `default="none"` |
197
+ | Directional slide | "Forward / back" | `<Link transitionTypes={["nav-forward"]}>` + `enter`/`exit` keyed by type |
198
+ | Same-route crossfade | "Same place, different content" | `key={slug}` + `share="auto"` `enter="auto"` |
199
+
200
+ Shared-element morph is the most common and works with zero CSS — wrap both the
201
+ source and destination element with the same `name`:
202
+
203
+ ```tsx
204
+ // grid thumbnail
205
+ <ViewTransition name={`photo-${photo.id}`}>
206
+ <Image src={photo.src} alt={photo.title} />
207
+ </ViewTransition>
208
+
209
+ // detail page hero — same name
210
+ <ViewTransition name={`photo-${photo.id}`}>
211
+ <Image src={photo.src} alt={photo.title} fill />
212
+ </ViewTransition>
213
+ ```
214
+
215
+ React matches the names across the old/new route and animates size and
216
+ position. Customize with `share="morph"` and `::view-transition-group(.morph)`
217
+ CSS. Respect `prefers-reduced-motion` by zeroing animation durations on the
218
+ `::view-transition-*` pseudo-elements.
219
+
220
+ Patterns 2–4 (CSS keyframes, directional/Suspense examples):
221
+ [Designing view transitions](https://nextjs.org/docs/app/guides/view-transitions).
222
+
223
+ ### Motion Library
224
+
225
+ For complex animations:
226
+
227
+ ```bash
228
+ bun add motion
229
+ ```
230
+
231
+ ```tsx
232
+ "use client"
233
+
234
+ import { motion, HTMLMotionProps } from "motion/react"
235
+
236
+ interface FadeInProps extends HTMLMotionProps<"div"> {
237
+ delay?: number
238
+ duration?: number
239
+ direction?: "up" | "down" | "left" | "right" | "none"
240
+ }
241
+
242
+ export function FadeIn({
243
+ children,
244
+ className,
245
+ delay = 0,
246
+ duration = 0.5,
247
+ direction = "up",
248
+ ...props
249
+ }: FadeInProps) {
250
+ const directions = {
251
+ up: { y: 20, x: 0 },
252
+ down: { y: -20, x: 0 },
253
+ left: { x: 20, y: 0 },
254
+ right: { x: -20, y: 0 },
255
+ none: { x: 0, y: 0 },
256
+ }
257
+
258
+ return (
259
+ <motion.div
260
+ initial={{ opacity: 0, ...directions[direction] }}
261
+ whileInView={{ opacity: 1, x: 0, y: 0 }}
262
+ viewport={{ once: true, margin: "-50px" }}
263
+ transition={{ duration, delay, ease: "easeOut" }}
264
+ className={className}
265
+ {...props}
266
+ >
267
+ {children}
268
+ </motion.div>
269
+ )
270
+ }
271
+ ```
272
+
273
+ ### GSAP
274
+
275
+ For scroll-triggered and complex sequences:
276
+
277
+ ```bash
278
+ bun add gsap @gsap/react
279
+ ```
280
+
281
+ ```tsx
282
+ "use client"
283
+
284
+ import { useRef } from "react"
285
+ import { useGSAP } from "@gsap/react"
286
+ import gsap from "gsap"
287
+ import { ScrollTrigger } from "gsap/ScrollTrigger"
288
+
289
+ gsap.registerPlugin(ScrollTrigger)
290
+
291
+ export function ScrollReveal({ children }) {
292
+ const containerRef = useRef<HTMLDivElement>(null)
293
+
294
+ useGSAP(() => {
295
+ gsap.from(containerRef.current, {
296
+ opacity: 0,
297
+ y: 50,
298
+ scrollTrigger: {
299
+ trigger: containerRef.current,
300
+ start: "top 80%",
301
+ },
302
+ })
303
+ }, [])
304
+
305
+ return <div ref={containerRef}>{children}</div>
306
+ }
307
+ ```
308
+
309
+ ## Animation Decision Tree
310
+
311
+ ```text
312
+ Simple fade/slide on mount?
313
+ ├── Yes → CSS animation in globals.css
314
+ └── No ↓
315
+
316
+ Page/route transitions?
317
+ ├── Yes → View Transitions API or template.tsx
318
+ └── No ↓
319
+
320
+ Interactive hover/tap states?
321
+ ├── Yes → Tailwind transitions + Motion
322
+ └── No ↓
323
+
324
+ Scroll-triggered sequences?
325
+ ├── Yes → GSAP + ScrollTrigger
326
+ └── No → Evaluate if animation needed
327
+ ```
328
+
329
+ ## Performance Tips
330
+
331
+ 1. **Prefer CSS** - GPU-accelerated, no JS bundle
332
+ 2. **Use `will-change` sparingly** - Only for known animations
333
+ 3. **Avoid layout thrashing** - Animate `transform` and `opacity`
334
+ 4. **Lazy load Motion/GSAP** - Dynamic imports for non-critical animations
335
+
336
+ ```tsx
337
+ // Lazy load animation library
338
+ const MotionDiv = dynamic(
339
+ () => import("motion/react").then((mod) => mod.motion.div),
340
+ { ssr: false }
341
+ )
342
+ ```
343
+
344
+ ## Decorative Backgrounds
345
+
346
+ Reusable patterns for visual atmosphere and section hierarchy.
347
+
348
+ ### Grid Pattern
349
+
350
+ ```tsx
351
+ import { cn } from "@/lib/utils"
352
+
353
+ export function GridBackground({
354
+ children,
355
+ className,
356
+ size = 20
357
+ }: {
358
+ children: React.ReactNode
359
+ className?: string
360
+ size?: number
361
+ }) {
362
+ return (
363
+ <div className={cn("relative", className)}>
364
+ <div
365
+ className={cn(
366
+ "absolute inset-0 -z-10",
367
+ "[background-image:linear-gradient(to_right,var(--border)_1px,transparent_1px),linear-gradient(to_bottom,var(--border)_1px,transparent_1px)]"
368
+ )}
369
+ style={{ backgroundSize: `${size}px ${size}px` }}
370
+ />
371
+ {children}
372
+ </div>
373
+ )
374
+ }
375
+ ```
376
+
377
+ ### Dot Pattern
378
+
379
+ ```tsx
380
+ export function DotBackground({
381
+ children,
382
+ className
383
+ }: {
384
+ children: React.ReactNode
385
+ className?: string
386
+ }) {
387
+ return (
388
+ <div className={cn("relative", className)}>
389
+ <div
390
+ className={cn(
391
+ "absolute inset-0 -z-10",
392
+ "[background-size:20px_20px]",
393
+ "[background-image:radial-gradient(color-mix(in_oklab,var(--muted-foreground)_30%,transparent)_1px,transparent_1px)]"
394
+ )}
395
+ />
396
+ {children}
397
+ </div>
398
+ )
399
+ }
400
+ ```
401
+
402
+ ### Radial Gradient Hero
403
+
404
+ ```tsx
405
+ export function GradientHero({ children }: { children: React.ReactNode }) {
406
+ return (
407
+ <div className="relative min-h-screen">
408
+ <div
409
+ aria-hidden
410
+ className="fixed inset-0 -z-10"
411
+ style={{
412
+ background: "radial-gradient(125% 125% at 50% 10%, var(--background) 40%, var(--primary) 100%)"
413
+ }}
414
+ />
415
+ {children}
416
+ </div>
417
+ )
418
+ }
419
+ ```
420
+
421
+ ### Faded Edge Effect
422
+
423
+ Combine with grid/dot for vignette:
424
+
425
+ ```tsx
426
+ <div className="relative">
427
+ <GridBackground className="absolute inset-0" />
428
+ <div className="pointer-events-none absolute inset-0 bg-background [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]" />
429
+ {/* Content */}
430
+ </div>
431
+ ```
432
+
433
+ ### Animated Spotlight
434
+
435
+ For premium hero sections. Requires `motion`:
436
+
437
+ ```tsx
438
+ "use client"
439
+
440
+ import { motion } from "motion/react"
441
+ import { cn } from "@/lib/utils"
442
+
443
+ export function Spotlight({ className }: { className?: string }) {
444
+ return (
445
+ <motion.div
446
+ className={cn(
447
+ "pointer-events-none fixed inset-0 -z-10 overflow-hidden",
448
+ className
449
+ )}
450
+ aria-hidden
451
+ >
452
+ <motion.div
453
+ className="absolute top-0 left-1/2 h-[60vh] w-[80vw] -translate-x-1/2 rounded-full opacity-20 blur-3xl"
454
+ style={{
455
+ background:
456
+ "radial-gradient(ellipse, color-mix(in oklab, var(--primary) 30%, transparent), transparent 70%)",
457
+ }}
458
+ animate={{ x: ["-10%", "10%", "-10%"] }}
459
+ transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
460
+ />
461
+ </motion.div>
462
+ )
463
+ }
464
+ ```
465
+
466
+ Combine with DotBackground for depth:
467
+
468
+ ```tsx
469
+ <div className="relative min-h-screen bg-background dark:bg-black">
470
+ <Spotlight />
471
+ <DotBackground className="absolute inset-0 opacity-30" />
472
+ <div className="relative z-10">{children}</div>
473
+ </div>
474
+ ```
475
+
476
+ For more creative direction (custom textures, particles, dramatic effects), apply `/frontend-design` thinking.
477
+
478
+ ### Section Wrapper
479
+
480
+ For sections that need different theme context:
481
+
482
+ ```tsx
483
+ type SectionProps = {
484
+ children: React.ReactNode
485
+ variant?: "default" | "muted" | "inverted"
486
+ className?: string
487
+ }
488
+
489
+ export function Section({ children, variant = "default", className }: SectionProps) {
490
+ return (
491
+ <section
492
+ className={cn(
493
+ "relative py-24",
494
+ variant === "muted" && "bg-muted",
495
+ variant === "inverted" && "bg-foreground text-background [&_*]:border-background/20",
496
+ className
497
+ )}
498
+ >
499
+ {children}
500
+ </section>
501
+ )
502
+ }
503
+ ```
504
+
505
+ ### Background Decision Tree
506
+
507
+ ```text
508
+ Full-page ambient effect?
509
+ ├── Static → Fixed radial gradient (GradientHero)
510
+ ├── Animated → Spotlight + DotBackground
511
+ ├── Premium → Apply /frontend-design thinking
512
+ └── No ↓
513
+
514
+ Subtle texture for depth?
515
+ ├── Grid → Technical/dashboard feel
516
+ ├── Dots → Softer/organic feel
517
+ └── No ↓
518
+
519
+ Section contrast needed?
520
+ ├── Yes → Section wrapper with variant
521
+ └── No → Standard bg-background
522
+ ```
523
+
524
+ ### File Organization
525
+
526
+ ```text
527
+ components/
528
+ ├── ui/ # shadcn primitives
529
+ ├── backgrounds/ # Grid, Dot, Gradient patterns
530
+ └── animations/ # FadeIn, ScrollReveal
531
+ ```
532
+
533
+ ## Optional Utilities
534
+
535
+ ### Scrollbar Hide
536
+
537
+ `shadcn/tailwind.css` already ships a `no-scrollbar` utility, so a shadcn project
538
+ needs no extra package:
539
+
540
+ ```tsx
541
+ <div className="overflow-y-auto no-scrollbar">
542
+ {/* Scrollable content without visible scrollbar */}
543
+ </div>
544
+ ```
545
+
546
+ Only reach for a package in a project that doesn't import `shadcn/tailwind.css`:
547
+
548
+ ```bash
549
+ bun add tailwind-scrollbar-hide
550
+ ```
551
+
552
+ ```css
553
+ /* globals.css (Tailwind v4 — no config file needed) */
554
+ @import "tailwind-scrollbar-hide/v4";
555
+ ```
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: sf-scaffold
3
+ description: Scaffold a new Thor Commerce storefront from this package's static templates using @thorprovider/blocks and @thorprovider/adapters (Medusa)
4
+ ---
5
+
6
+ # sf-scaffold
7
+
8
+ Scaffold a new Thor Commerce storefront. This skill is **self-contained**: it generates from this package's `templates/` — it NEVER reads `projects/electrostore` or any machine-global skill.
9
+
10
+ ## Package resources (use these)
11
+
12
+ - `templates/app/` — the static storefront templates (see below)
13
+ - `recipes/recipes.json`, `recipes/sections.json` — view recipes (for `/sf-add-view`)
14
+ - `skills/nextjs-shadcn/` — vendored Next.js + shadcn setup skill
15
+ - `skills/shadcn-theming/` — vendored theming skill
16
+ - `skills/json-render-next/` — vendored json-render Next.js reference (NextAppSpec, `createNextApp`, `PageRenderer`, `useNextApp`)
17
+ - `skills/json-render-core/` — vendored json-render core reference (catalogs, schemas, spec shape)
18
+
19
+ The json-render references are consult-when-needed: templates are the primary source. When you must adapt or extend the generated `runtime.ts`, `catalog.ts`, or `spec/` beyond the templates, consult `json-render-next` (runtime/app wiring) and `json-render-core` (catalog/spec) instead of working from memory.
20
+
21
+ ## Resolving package assets
22
+
23
+ These assets live **inside the installed package**, not in the target project. Resolve the package root in this order:
24
+
25
+ 1. If `.opencode/.create-storefront-root` exists in the target project, read it — the installer writes the absolute package root there.
26
+ 2. Otherwise, if this skill was loaded from a path under `.opencode/skills/sf-scaffold/`, walk upward from there to the package root.
27
+ 3. Read templates from `<package-root>/templates/app/`.
28
+
29
+ If the package root cannot be resolved, STOP and tell the user to re-run the installer.
30
+
31
+ ## Template layout
32
+
33
+ ```
34
+ templates/app/
35
+ app/
36
+ globals.css
37
+ layout.tsx
38
+ [[...slug]]/page.tsx
39
+ [[...slug]]/renderer.tsx
40
+ lib/__STOREFRONT__/
41
+ catalog.ts
42
+ handlers.ts
43
+ registry.tsx
44
+ runtime.ts
45
+ state.ts
46
+ spec/home.ts
47
+ spec/index.ts
48
+ spec/types.ts
49
+ ```
50
+
51
+ ## Placeholders (substitute everywhere)
52
+
53
+ | Placeholder | Meaning | Example |
54
+ |---|---|---|
55
+ | `__STOREFRONT__` | kebab-case storefront dir name | `my-store` |
56
+ | `__STOREFRONT_CAMEL__` | PascalCase identifier | `myStore` |
57
+ | `__SITE_NAME__` | human site name | `My Store` |
58
+
59
+ ## Stack constraints (enforce)
60
+
61
+ - UI: only `@thorprovider/blocks`
62
+ - Data: only `@thorprovider/adapters` + `@thorprovider/storefronts/commerce`
63
+ - Never import `@thorprovider/medusa-extended`
64
+ - Do NOT create custom blocks unless the user explicitly authorizes it
65
+
66
+ ## Workflow
67
+
68
+ ### 1. Wizard
69
+ Use the `question` tool to collect:
70
+ 1. Storefront name (required, kebab-case) — becomes `lib/<name>/`
71
+ 2. Medusa backend URL (optional, default `http://localhost:9000`)
72
+ 3. Site name (optional, default = storefront name)
73
+ 4. Primary brand color (optional)
74
+
75
+ ### 2. Preconditions (BEFORE writing anything)
76
+ - Empty dir or existing Next.js project? Unrelated files → WARN + confirm.
77
+ - If `lib/<name>/` exists → ERROR, stop, suggest `/sf-add-view` or `/sf-view`.
78
+ - Confirm `.opencode/` exists in the project.
79
+ Report each check before proceeding.
80
+
81
+ ### 3. Next.js + shadcn base
82
+ - Empty dir → follow `skills/nextjs-shadcn/SKILL.md` to set up Next.js + shadcn/ui.
83
+ - Existing Next.js project → skip.
84
+
85
+ ### 4. Dependencies
86
+ ```bash
87
+ pnpm add @thorprovider/blocks @thorprovider/adapters @thorprovider/storefronts @json-render/core @json-render/react @json-render/next motion
88
+ ```
89
+
90
+ ### 5. Copy templates
91
+ Copy every file from `templates/app/` into the target project:
92
+ - rename the `lib/__STOREFRONT__/` directory to `lib/<name>/`
93
+ - replace `__STOREFRONT__`, `__STOREFRONT_CAMEL__`, `__SITE_NAME__` in all files.
94
+
95
+ ### 6. Environment
96
+ Create `.env.local`:
97
+ ```
98
+ MEDUSA_BACKEND_URL=<url or http://localhost:9000>
99
+ MEDUSA_REGION_ID=
100
+ MEDUSA_PUBLISHABLE_KEY=
101
+ ```
102
+
103
+ ### 7. Theme (optional)
104
+ If a brand color was given, follow `skills/shadcn-theming/SKILL.md` to update OKLCH light+dark pairs in `app/globals.css`.
105
+
106
+ ### 8. Success
107
+ Report created files and next steps (`pnpm dev`, then `/sf-add-view`, `/sf-theme`).
108
+
109
+ ## Error handling
110
+ - Invalid name → re-prompt.
111
+ - `lib/<name>/` exists → stop, suggest `/sf-add-view` / `/sf-view`.
112
+ - List exactly what was written and what failed; never leave partial scaffolding silently.
113
+
114
+ ## Generation headers
115
+ Prepend to each copied file:
116
+ ```
117
+ // Generated by @thorprovider/create-storefront (sf-scaffold) from templates/app/<path>
118
+ ```
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: sf-theme-gen
3
+ description: Customize a Thor Commerce storefront's OKLCH color tokens (light/dark), typography, and identity/SEO metadata
4
+ ---
5
+
6
+ # sf-theme-gen
7
+
8
+ Customize a storefront's theme and identity. Self-contained: uses the vendored theming skill, never a machine-global skill.
9
+
10
+ ## Scope
11
+
12
+ | Area | File |
13
+ |---|---|
14
+ | Design tokens (shadcn) | `app/globals.css` |
15
+ | Typography + metadata | `app/layout.tsx` |
16
+
17
+ ## Vendored skill
18
+ Follow `skills/shadcn-theming/SKILL.md` for OKLCH pair rules and contrast.
19
+
20
+ ## Color rules
21
+ - Colors are CSS variables, never raw Tailwind color utilities.
22
+ - OKLCH only; define complete background/foreground pairs.
23
+ - Lightness rule: bg `L < 0.55` → fg `L >= 0.93`; bg `L >= 0.55` → fg `L <= 0.20`.
24
+ - Named accents can use `accentColorToOklch(name)` from `@thorprovider/storefronts/render-core/theme`.
25
+
26
+ ## Workflow
27
+
28
+ 1. Use the `question` tool to ask what to customize: colors, typography, identity, SEO, Open Graph.
29
+ 2. **Colors**: follow `skills/shadcn-theming/SKILL.md`; update BOTH `:root` (light) and `.dark` blocks in `app/globals.css`, keeping the `@theme inline` mapping intact.
30
+ 3. **Pairs**: every changed color gets its foreground pair in both modes; verify the lightness rule.
31
+ 4. **Typography**: load the font with `next/font` in `app/layout.tsx`; point `--font-sans` in `globals.css` at the new variable; keep body >= 1rem / line-height 1.5.
32
+ 5. **Identity**: update the `metadata` object in `app/layout.tsx` (title, description) and add Open Graph + Twitter Card fields. Research the current Next.js Metadata API before writing.
33
+ 6. **Verify**: run the dev server; confirm both color modes, font, and head metadata. `pnpm typecheck` passes.
34
+
35
+ ## Error handling
36
+ - Invalid color input → re-prompt (accept `<name>`, `#hex`, `oklch(...)`).
37
+ - No `lib/<name>/` → suggest `/sf-init`, stop.
38
+ - Unknown token key → check `themeTokenKeys` in `@thorprovider/storefronts/contracts` first.
39
+
40
+ ## Generation headers
41
+ ```
42
+ // Themed by @thorprovider/create-storefront (sf-theme-gen)
43
+ ```
44
+ Never remove existing tokens; only override values.