@thorprovider/storefront 0.3.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 (109) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +333 -0
  3. package/assets/templates/app/app/[[...slug]]/page.tsx +17 -0
  4. package/assets/templates/app/app/[[...slug]]/renderer.tsx +10 -0
  5. package/assets/templates/app/app/globals.css +101 -0
  6. package/assets/templates/app/app/layout.tsx +35 -0
  7. package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +88 -0
  8. package/assets/templates/app/lib/__STOREFRONT__/handlers.ts +42 -0
  9. package/assets/templates/app/lib/__STOREFRONT__/mappers.ts +47 -0
  10. package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +98 -0
  11. package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +17 -0
  12. package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +48 -0
  13. package/assets/templates/app/lib/__STOREFRONT__/spec/page-root.ts +26 -0
  14. package/assets/templates/app/lib/__STOREFRONT__/spec/types.ts +14 -0
  15. package/assets/templates/app/lib/__STOREFRONT__/state.ts +35 -0
  16. package/assets/templates/app/lib/__STOREFRONT__/views/index.ts +7 -0
  17. package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.tsx +29 -0
  18. package/assets/templates/app/lib/__STOREFRONT__/views/sections/logoCloud.tsx +29 -0
  19. package/assets/templates/app/lib/__STOREFRONT__/views/sections/pricing.tsx +33 -0
  20. package/assets/templates/app/lib/__STOREFRONT__/views/sections/statistics.tsx +29 -0
  21. package/assets/templates/app/lib/__STOREFRONT__/views/sections/testimonials.tsx +28 -0
  22. package/assets/templates/app/lib/__STOREFRONT__/views/types.ts +46 -0
  23. package/assets/templates/views/home/index.tsx +142 -0
  24. package/assets/templates/views/home/registry.tsx +65 -0
  25. package/bin/storefront.js +531 -0
  26. package/commands/sf-add-view.md +26 -0
  27. package/commands/sf-theme.md +20 -0
  28. package/commands/sf-view.md +25 -0
  29. package/package.json +48 -0
  30. package/recipes/archetype.schema.json +39 -0
  31. package/recipes/archetypes.json +148 -0
  32. package/recipes/recipe.schema.json +59 -0
  33. package/recipes/recipes.json +90 -0
  34. package/recipes/sections.json +46 -0
  35. package/recipes/validate.mjs +190 -0
  36. package/scripts/render-templates.mjs +255 -0
  37. package/scripts/sync-assets.mjs +87 -0
  38. package/skills/building-storefronts/SKILL.md +178 -0
  39. package/skills/building-storefronts/references/frontend-integration.md +229 -0
  40. package/skills/json-render-core/SKILL.md +291 -0
  41. package/skills/json-render-next/SKILL.md +194 -0
  42. package/skills/json-render-react/SKILL.md +298 -0
  43. package/skills/json-render-remotion/SKILL.md +111 -0
  44. package/skills/json-render-shadcn/SKILL.md +159 -0
  45. package/skills/json-render-solid/SKILL.md +204 -0
  46. package/skills/nextjs-shadcn/SKILL.md +367 -0
  47. package/skills/nextjs-shadcn/references/architecture.md +499 -0
  48. package/skills/nextjs-shadcn/references/project-setup.md +162 -0
  49. package/skills/nextjs-shadcn/references/shadcn-platform.md +261 -0
  50. package/skills/nextjs-shadcn/references/sidebar.md +274 -0
  51. package/skills/nextjs-shadcn/references/styling.md +555 -0
  52. package/skills/sf-theme-gen/SKILL.md +61 -0
  53. package/skills/sf-view-gen/SKILL.md +116 -0
  54. package/skills/sf-view-gen/assets/recipes/archetypes.json +148 -0
  55. package/skills/sf-view-gen/assets/recipes/recipes.json +90 -0
  56. package/skills/sf-view-gen/assets/recipes/sections.json +46 -0
  57. package/skills/sf-view-gen/assets/templates/views/category/index.tsx +86 -0
  58. package/skills/sf-view-gen/assets/templates/views/category/registry.tsx +48 -0
  59. package/skills/sf-view-gen/assets/templates/views/checkout/index.tsx +192 -0
  60. package/skills/sf-view-gen/assets/templates/views/checkout/registry.tsx +45 -0
  61. package/skills/sf-view-gen/assets/templates/views/product/index.tsx +122 -0
  62. package/skills/sf-view-gen/assets/templates/views/product/registry.tsx +49 -0
  63. package/skills/sf-view-gen/assets/templates/views/sections/faq.client.tsx +20 -0
  64. package/skills/sf-view-gen/assets/templates/views/sections/faq.tsx +21 -0
  65. package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.client.tsx +18 -0
  66. package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.tsx +21 -0
  67. package/skills/sf-view-gen/assets/templates/views/sections/pricing.client.tsx +20 -0
  68. package/skills/sf-view-gen/assets/templates/views/sections/pricing.tsx +23 -0
  69. package/skills/sf-view-gen/assets/templates/views/sections/statistics.client.tsx +18 -0
  70. package/skills/sf-view-gen/assets/templates/views/sections/statistics.tsx +21 -0
  71. package/skills/sf-view-gen/assets/templates/views/sections/testimonials.client.tsx +19 -0
  72. package/skills/sf-view-gen/assets/templates/views/sections/testimonials.tsx +19 -0
  73. package/skills/sf-view-gen/assets/templates/views/user-panel/index.tsx +168 -0
  74. package/skills/sf-view-gen/assets/templates/views/user-panel/registry.tsx +49 -0
  75. package/skills/sf-view-gen/references/views.md +69 -0
  76. package/skills/sf-view-gen/scripts/validate.mjs +190 -0
  77. package/skills/shadcn-component-discovery/SKILL.md +273 -0
  78. package/skills/shadcn-component-discovery/references/registries.md +226 -0
  79. package/skills/shadcn-theming/SKILL.md +104 -0
  80. package/skills/shadcn-theming/references/templates/theme-setup.md +109 -0
  81. package/skills/shadcn-theming/references/theming-guide.md +90 -0
  82. package/skills/storefront-best-practices/SKILL.md +421 -0
  83. package/skills/storefront-best-practices/reference/components/breadcrumbs.md +123 -0
  84. package/skills/storefront-best-practices/reference/components/cart-popup.md +189 -0
  85. package/skills/storefront-best-practices/reference/components/country-selector.md +298 -0
  86. package/skills/storefront-best-practices/reference/components/footer.md +112 -0
  87. package/skills/storefront-best-practices/reference/components/hero.md +241 -0
  88. package/skills/storefront-best-practices/reference/components/megamenu.md +239 -0
  89. package/skills/storefront-best-practices/reference/components/navbar.md +397 -0
  90. package/skills/storefront-best-practices/reference/components/popups.md +221 -0
  91. package/skills/storefront-best-practices/reference/components/product-card.md +125 -0
  92. package/skills/storefront-best-practices/reference/components/product-reviews.md +217 -0
  93. package/skills/storefront-best-practices/reference/components/product-slider.md +174 -0
  94. package/skills/storefront-best-practices/reference/components/search.md +101 -0
  95. package/skills/storefront-best-practices/reference/connecting-to-backend.md +391 -0
  96. package/skills/storefront-best-practices/reference/design.md +388 -0
  97. package/skills/storefront-best-practices/reference/features/promotions.md +307 -0
  98. package/skills/storefront-best-practices/reference/features/wishlist.md +230 -0
  99. package/skills/storefront-best-practices/reference/layouts/account.md +380 -0
  100. package/skills/storefront-best-practices/reference/layouts/cart.md +316 -0
  101. package/skills/storefront-best-practices/reference/layouts/checkout.md +486 -0
  102. package/skills/storefront-best-practices/reference/layouts/home-page.md +264 -0
  103. package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +231 -0
  104. package/skills/storefront-best-practices/reference/layouts/product-details.md +527 -0
  105. package/skills/storefront-best-practices/reference/layouts/product-listing.md +520 -0
  106. package/skills/storefront-best-practices/reference/layouts/static-pages.md +356 -0
  107. package/skills/storefront-best-practices/reference/medusa.md +307 -0
  108. package/skills/storefront-best-practices/reference/mobile-responsiveness.md +183 -0
  109. package/skills/storefront-best-practices/reference/seo.md +195 -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) - `yarn add lucide-react`
127
+ 2. **tabler** - `yarn add @tabler/icons-react`
128
+ 3. **hugeicons** - `yarn add @hugeicons/react @hugeicons/core-free-icons` (the old `hugeicons-react` package is deprecated)
129
+ 4. **phosphor** - `yarn add @phosphor-icons/react`
130
+ 5. **remixicon** - `yarn 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
+ yarn 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
+ yarn 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
+ yarn 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,61 @@
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. This skill ships with everything it needs: it uses the vendored theming skill alongside it. When a choice is not resolved by those files, ask the user.
9
+
10
+ ## Source of truth
11
+
12
+ The workflow uses only the assets in this skill directory and the vendored `../shadcn-theming/` skill next to it. When a required choice is not determined there, ask the user.
13
+
14
+ ## Inputs (the only target-project facts this skill reads)
15
+
16
+ - the existence of the target project's `package.json`
17
+ - the existence of `lib/<name>/`
18
+ - the existence of the project's `.opencode/`
19
+ - the values returned by the wizard (which area to customize, and its value)
20
+
21
+ ## Outputs (what this skill produces)
22
+
23
+ - generated files: `app/globals.css` and `app/layout.tsx`
24
+ - declared setup commands: the dev server and typecheck commands it reports
25
+ - a summary listing every file edited and every command run
26
+
27
+ ## Scope
28
+
29
+ | Area | File |
30
+ |---|---|
31
+ | Design tokens (shadcn) | `app/globals.css` |
32
+ | Typography + metadata | `app/layout.tsx` |
33
+
34
+ ## Vendored skill
35
+ Follow `../shadcn-theming/SKILL.md` for OKLCH pair rules and contrast. Paths are relative to this `SKILL.md`.
36
+
37
+ ## Color rules
38
+ - Colors are CSS variables, never raw Tailwind color utilities.
39
+ - OKLCH only; define complete background/foreground pairs.
40
+ - Lightness rule: bg `L < 0.55` → fg `L >= 0.93`; bg `L >= 0.55` → fg `L <= 0.20`.
41
+ - Named accents can use `accentColorToOklch(name)` from `@thorprovider/runtime/render-core/theme`.
42
+
43
+ ## Workflow
44
+
45
+ 1. Use the `question` tool to ask what to customize: colors, typography, identity, SEO, Open Graph.
46
+ 2. **Colors**: follow `../shadcn-theming/SKILL.md`; update BOTH `:root` (light) and `.dark` blocks in `app/globals.css`, keeping the `@theme inline` mapping intact.
47
+ 3. **Pairs**: every changed color gets its foreground pair in both modes; verify the lightness rule.
48
+ 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.
49
+ 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.
50
+ 6. **Verify**: run the dev server; confirm both color modes, font, and head metadata. `yarn typecheck` passes.
51
+
52
+ ## Error handling
53
+ - Invalid color input → re-prompt (accept `<name>`, `#hex`, `oklch(...)`).
54
+ - No `lib/<name>/` → run `npx @thorprovider/storefront create`, stop.
55
+ - Unknown token key → check `themeTokenKeys` in `@thorprovider/runtime/contracts` first.
56
+
57
+ ## Generation headers
58
+ ```
59
+ // Themed by @thorprovider/storefront (sf-theme-gen)
60
+ ```
61
+ Never remove existing tokens; only override values.