create-brainerce-store 1.51.0 → 1.52.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 (173) hide show
  1. package/README.md +71 -0
  2. package/dist/index.js +24 -80
  3. package/messages/en.json +32 -0
  4. package/messages/he.json +32 -0
  5. package/package.json +1 -1
  6. package/templates/nextjs/base/.claude/commands/design.md +9 -0
  7. package/templates/nextjs/base/AI-GUIDE.md +52 -3
  8. package/templates/nextjs/base/CLAUDE.md +10 -0
  9. package/templates/nextjs/base/package.json.ejs +52 -39
  10. package/templates/nextjs/base/src/app/globals.css +36 -30
  11. package/templates/nextjs/base/src/components/checkout/payment-step.tsx +14 -10
  12. package/templates/nextjs/base/src/components/ui/accordion.tsx +53 -0
  13. package/templates/nextjs/base/src/components/ui/badge.tsx +32 -0
  14. package/templates/nextjs/base/src/components/ui/button.tsx +49 -0
  15. package/templates/nextjs/base/src/components/ui/card.tsx +55 -0
  16. package/templates/nextjs/base/src/components/ui/checkbox.tsx +28 -0
  17. package/templates/nextjs/base/src/components/ui/dialog.tsx +107 -0
  18. package/templates/nextjs/base/src/components/ui/input.tsx +22 -0
  19. package/templates/nextjs/base/src/components/ui/label.tsx +21 -0
  20. package/templates/nextjs/base/src/components/ui/radio-group.tsx +38 -0
  21. package/templates/nextjs/base/src/components/ui/select.tsx +153 -0
  22. package/templates/nextjs/base/src/components/ui/separator.tsx +26 -0
  23. package/templates/nextjs/base/src/components/ui/sheet.tsx +125 -0
  24. package/templates/nextjs/base/src/components/ui/skeleton.tsx +7 -0
  25. package/templates/nextjs/base/src/components/ui/tabs.tsx +55 -0
  26. package/templates/nextjs/base/src/components/ui/textarea.tsx +21 -0
  27. package/templates/nextjs/base/src/components/ui/tooltip.tsx +32 -0
  28. package/templates/nextjs/base/src/ui/cart/cart-bundle-offer.tsx +17 -11
  29. package/templates/nextjs/base/src/ui/cart/cart-item.tsx +2 -8
  30. package/templates/nextjs/base/src/ui/cart/cart-nudges.tsx +28 -39
  31. package/templates/nextjs/base/src/ui/cart/cart-summary.tsx +3 -1
  32. package/templates/nextjs/base/src/ui/cart/cart-upgrade-banner.tsx +8 -23
  33. package/templates/nextjs/base/src/ui/cart/cart-view.tsx +18 -27
  34. package/templates/nextjs/base/src/ui/cart/coupon-input.tsx +10 -21
  35. package/templates/nextjs/base/src/ui/cart/free-shipping-bar.tsx +2 -3
  36. package/templates/nextjs/base/src/ui/cart/reservation-countdown.tsx +95 -103
  37. package/templates/nextjs/base/src/ui/home/hero-section.tsx +4 -6
  38. package/templates/nextjs/base/src/ui/layout/announcement-bar.tsx.ejs +116 -125
  39. package/templates/nextjs/base/src/ui/layout/faq-section.tsx.ejs +90 -103
  40. package/templates/nextjs/base/src/ui/layout/header-account.tsx +2 -17
  41. package/templates/nextjs/base/src/ui/layout/language-switcher.tsx.ejs +80 -70
  42. package/templates/nextjs/base/src/ui/layout/site-footer.tsx.ejs +144 -164
  43. package/templates/nextjs/base/src/ui/layout/site-header.tsx.ejs +152 -182
  44. package/templates/nextjs/base/src/ui/product/customization-fields.tsx +456 -444
  45. package/templates/nextjs/base/src/ui/product/discount-badge.tsx +18 -22
  46. package/templates/nextjs/base/src/ui/product/frequently-bought-together.tsx +15 -27
  47. package/templates/nextjs/base/src/ui/product/modifier-group-selector.tsx +206 -175
  48. package/templates/nextjs/base/src/ui/product/price-display.tsx +3 -2
  49. package/templates/nextjs/base/src/ui/product/product-card.tsx +238 -271
  50. package/templates/nextjs/base/src/ui/product/product-client-section.tsx +455 -470
  51. package/templates/nextjs/base/src/ui/product/product-listing.tsx +96 -79
  52. package/templates/nextjs/base/src/ui/product/recommendation-section.tsx +102 -107
  53. package/templates/nextjs/base/src/ui/product/review-form.tsx +44 -43
  54. package/templates/nextjs/{designs/passepartout → base/src}/ui/product/reviews-section.tsx.ejs +108 -96
  55. package/templates/nextjs/base/src/ui/product/stock-badge.tsx +61 -63
  56. package/templates/nextjs/base/tailwind.config.ts +69 -42
  57. package/templates/nextjs/designs/{passepartout → atelier}/app-overlay/layout.tsx.ejs +23 -25
  58. package/templates/nextjs/designs/atelier/globals.css +396 -0
  59. package/templates/nextjs/designs/atelier/messages-patch/en.json +99 -0
  60. package/templates/nextjs/designs/atelier/messages-patch/he.json +99 -0
  61. package/templates/nextjs/designs/{passepartout → atelier}/ui/cart/cart-bundle-offer.tsx +110 -111
  62. package/templates/nextjs/designs/atelier/ui/cart/cart-drawer.tsx +163 -0
  63. package/templates/nextjs/designs/atelier/ui/cart/cart-item.tsx +140 -0
  64. package/templates/nextjs/designs/atelier/ui/cart/cart-nudges.tsx +34 -0
  65. package/templates/nextjs/designs/atelier/ui/cart/cart-summary.tsx +107 -0
  66. package/templates/nextjs/designs/{passepartout → atelier}/ui/cart/cart-upgrade-banner.tsx +123 -141
  67. package/templates/nextjs/designs/atelier/ui/cart/cart-view.tsx +147 -0
  68. package/templates/nextjs/designs/atelier/ui/cart/coupon-input.tsx +142 -0
  69. package/templates/nextjs/designs/{passepartout → atelier}/ui/cart/free-shipping-bar.tsx +77 -62
  70. package/templates/nextjs/designs/{passepartout → atelier}/ui/cart/reservation-countdown.tsx +89 -103
  71. package/templates/nextjs/designs/atelier/ui/home/benefits-band.tsx +34 -0
  72. package/templates/nextjs/designs/atelier/ui/home/category-tiles.tsx +148 -0
  73. package/templates/nextjs/designs/atelier/ui/home/discount-banner-strip.tsx +27 -0
  74. package/templates/nextjs/designs/atelier/ui/home/editorial-band.tsx +73 -0
  75. package/templates/nextjs/designs/atelier/ui/home/featured-products-section.tsx +36 -0
  76. package/templates/nextjs/designs/atelier/ui/home/hero-section.tsx +148 -0
  77. package/templates/nextjs/designs/atelier/ui/home/home-client.tsx +54 -0
  78. package/templates/nextjs/designs/atelier/ui/home/newsletter-section.tsx +78 -0
  79. package/templates/nextjs/designs/atelier/ui/home/testimonials-band.tsx +46 -0
  80. package/templates/nextjs/designs/atelier/ui/layout/announcement-bar.tsx +118 -0
  81. package/templates/nextjs/designs/atelier/ui/layout/faq-section.tsx +96 -0
  82. package/templates/nextjs/designs/atelier/ui/layout/header-account.tsx +36 -0
  83. package/templates/nextjs/designs/atelier/ui/layout/header-cart.tsx +36 -0
  84. package/templates/nextjs/designs/atelier/ui/layout/language-switcher.tsx.ejs +137 -0
  85. package/templates/nextjs/designs/atelier/ui/layout/nav-url.ts +14 -0
  86. package/templates/nextjs/designs/atelier/ui/layout/rich-text-block.tsx +34 -0
  87. package/templates/nextjs/designs/atelier/ui/layout/site-footer.tsx.ejs +141 -0
  88. package/templates/nextjs/designs/atelier/ui/layout/site-header.tsx.ejs +138 -0
  89. package/templates/nextjs/designs/atelier/ui/product/customization-fields.tsx +466 -0
  90. package/templates/nextjs/designs/{passepartout → atelier}/ui/product/discount-badge.tsx +17 -22
  91. package/templates/nextjs/designs/{passepartout → atelier}/ui/product/frequently-bought-together.tsx +196 -205
  92. package/templates/nextjs/designs/atelier/ui/product/modifier-group-selector.tsx +193 -0
  93. package/templates/nextjs/designs/atelier/ui/product/price-display.tsx +69 -0
  94. package/templates/nextjs/designs/atelier/ui/product/product-card.tsx +260 -0
  95. package/templates/nextjs/designs/atelier/ui/product/product-client-section.tsx +471 -0
  96. package/templates/nextjs/designs/atelier/ui/product/product-grid.tsx +47 -0
  97. package/templates/nextjs/designs/atelier/ui/product/product-listing.tsx +260 -0
  98. package/templates/nextjs/designs/atelier/ui/product/recommendation-section.tsx +95 -0
  99. package/templates/nextjs/designs/{passepartout → atelier}/ui/product/review-form.tsx +267 -294
  100. package/templates/nextjs/designs/atelier/ui/product/reviews-section.tsx.ejs +148 -0
  101. package/templates/nextjs/designs/atelier/ui/product/stock-badge.tsx +66 -0
  102. package/templates/nextjs/designs/atelier/ui/product/variant-selector.tsx +206 -0
  103. package/templates/nextjs/designs/atelier/ui/shared/cdn-image.tsx +29 -0
  104. package/templates/nextjs/designs/{passepartout → atelier}/ui/shared/fly-to-cart.ts +86 -85
  105. package/templates/nextjs/designs/atelier/ui/shared/icons.tsx +269 -0
  106. package/templates/nextjs/designs/atelier/ui/shared/loading-spinner.tsx +64 -0
  107. package/templates/nextjs/designs/atelier/ui/shared/reveal.tsx +71 -0
  108. package/templates/nextjs/designs/atelier/ui/shared/select-menu.tsx +125 -0
  109. package/templates/nextjs/ui-canvas/cart/cart-bundle-offer.tsx +2 -0
  110. package/templates/nextjs/ui-canvas/cart/cart-item.tsx +2 -0
  111. package/templates/nextjs/ui-canvas/cart/cart-nudges.tsx +2 -0
  112. package/templates/nextjs/ui-canvas/cart/cart-summary.tsx +2 -0
  113. package/templates/nextjs/ui-canvas/cart/cart-upgrade-banner.tsx +2 -0
  114. package/templates/nextjs/ui-canvas/cart/cart-view.tsx +2 -2
  115. package/templates/nextjs/ui-canvas/cart/coupon-input.tsx +2 -0
  116. package/templates/nextjs/ui-canvas/cart/free-shipping-bar.tsx +2 -0
  117. package/templates/nextjs/ui-canvas/cart/reservation-countdown.tsx +2 -0
  118. package/templates/nextjs/ui-canvas/home/discount-banner-strip.tsx +1 -1
  119. package/templates/nextjs/ui-canvas/home/featured-products-section.tsx +1 -1
  120. package/templates/nextjs/ui-canvas/home/hero-section.tsx +1 -1
  121. package/templates/nextjs/ui-canvas/home/home-client.tsx +1 -1
  122. package/templates/nextjs/ui-canvas/layout/announcement-bar.tsx.ejs +1 -1
  123. package/templates/nextjs/ui-canvas/layout/faq-section.tsx.ejs +2 -2
  124. package/templates/nextjs/ui-canvas/layout/header-account.tsx +1 -1
  125. package/templates/nextjs/ui-canvas/layout/language-switcher.tsx.ejs +2 -0
  126. package/templates/nextjs/ui-canvas/layout/rich-text-block.tsx.ejs +2 -0
  127. package/templates/nextjs/ui-canvas/layout/site-footer.tsx.ejs +2 -2
  128. package/templates/nextjs/ui-canvas/layout/site-header.tsx.ejs +2 -2
  129. package/templates/nextjs/ui-canvas/product/customization-fields.tsx +2 -0
  130. package/templates/nextjs/ui-canvas/product/discount-badge.tsx +2 -0
  131. package/templates/nextjs/ui-canvas/product/frequently-bought-together.tsx +2 -0
  132. package/templates/nextjs/ui-canvas/product/modifier-group-selector.tsx +2 -0
  133. package/templates/nextjs/ui-canvas/product/price-display.tsx +2 -0
  134. package/templates/nextjs/ui-canvas/product/product-card.tsx +1 -1
  135. package/templates/nextjs/ui-canvas/product/product-client-section.tsx +1 -1
  136. package/templates/nextjs/ui-canvas/product/product-grid.tsx +1 -1
  137. package/templates/nextjs/ui-canvas/product/product-listing.tsx +1 -1
  138. package/templates/nextjs/ui-canvas/product/recommendation-section.tsx +4 -0
  139. package/templates/nextjs/ui-canvas/product/review-form.tsx +29 -32
  140. package/templates/nextjs/ui-canvas/product/{reviews-section.tsx → reviews-section.tsx.ejs} +26 -8
  141. package/templates/nextjs/ui-canvas/product/stock-badge.tsx +2 -0
  142. package/templates/nextjs/ui-canvas/product/variant-selector.tsx +2 -0
  143. package/templates/nextjs/ui-canvas/shared/cdn-image.tsx +2 -0
  144. package/templates/nextjs/ui-canvas/shared/loading-spinner.tsx +2 -0
  145. package/templates/nextjs/base/src/ui/product/reviews-section.tsx +0 -85
  146. package/templates/nextjs/designs/passepartout/globals.css +0 -412
  147. package/templates/nextjs/designs/passepartout/messages-patch/en.json +0 -87
  148. package/templates/nextjs/designs/passepartout/messages-patch/he.json +0 -87
  149. package/templates/nextjs/designs/passepartout/ui/cart/cart-nudges.tsx +0 -39
  150. package/templates/nextjs/designs/passepartout/ui/cart/cart-view.tsx +0 -149
  151. package/templates/nextjs/designs/passepartout/ui/home/home-client.tsx +0 -401
  152. package/templates/nextjs/designs/passepartout/ui/layout/announcement-bar.tsx +0 -139
  153. package/templates/nextjs/designs/passepartout/ui/layout/cart-link.tsx +0 -45
  154. package/templates/nextjs/designs/passepartout/ui/layout/faq-section.tsx +0 -103
  155. package/templates/nextjs/designs/passepartout/ui/layout/site-footer.tsx +0 -159
  156. package/templates/nextjs/designs/passepartout/ui/layout/site-header.tsx.ejs +0 -155
  157. package/templates/nextjs/designs/passepartout/ui/layout/trust-icons.tsx +0 -60
  158. package/templates/nextjs/designs/passepartout/ui/layout/whatsapp-button.tsx +0 -34
  159. package/templates/nextjs/designs/passepartout/ui/product/price-display.tsx +0 -111
  160. package/templates/nextjs/designs/passepartout/ui/product/product-card.tsx +0 -265
  161. package/templates/nextjs/designs/passepartout/ui/product/product-client-section.tsx +0 -667
  162. package/templates/nextjs/designs/passepartout/ui/product/product-grid.tsx +0 -35
  163. package/templates/nextjs/designs/passepartout/ui/product/product-listing.tsx +0 -427
  164. package/templates/nextjs/designs/passepartout/ui/product/recommendation-section.tsx +0 -113
  165. package/templates/nextjs/designs/passepartout/ui/product/stock-badge.tsx +0 -52
  166. package/templates/nextjs/designs/passepartout/ui/product/variant-selector.tsx +0 -307
  167. package/templates/nextjs/designs/passepartout/ui/shared/loading-spinner.tsx +0 -33
  168. package/templates/nextjs/themes/luxury/globals.css +0 -399
  169. package/templates/nextjs/themes/luxury/theme.json +0 -23
  170. package/templates/nextjs/themes/minimal/globals.css +0 -30
  171. package/templates/nextjs/themes/minimal/theme.json +0 -23
  172. package/templates/nextjs/themes/playful/globals.css +0 -400
  173. package/templates/nextjs/themes/playful/theme.json +0 -23
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # create-brainerce-store
2
+
3
+ Scaffold a production-ready e-commerce storefront connected to [Brainerce](https://brainerce.com) — cart, checkout, variants, coupons, auth, SEO, and i18n wired out of the box.
4
+
5
+ ```bash
6
+ npm create brainerce-store@latest my-store -- --connection-id vc_xxxxxxxx
7
+ # or
8
+ pnpm create brainerce-store my-store --connection-id vc_xxxxxxxx
9
+ ```
10
+
11
+ Run it with no flags for a fully interactive setup. The CLI fetches your store's name, currency, language, and locales from the connection ID (`vc_*`, from your Brainerce dashboard), so the generated store matches the real channel from the first `dev` run.
12
+
13
+ ## The design
14
+
15
+ Every scaffold ships **Atelier** — a complete, AI-built storefront look (not just a color theme): warm editorial gallery with soft washes + glass surfaces, a floating hero collage, near-full-bleed product grid, styled popover dropdowns, a mini-cart drawer that opens on add-to-cart, and an RTL-safe fly-to-cart micro-interaction. Fully de-branded — driven by your store's name, catalog and dashboard content.
16
+
17
+ It's a starting point, not a lock-in: the entire look lives in `src/ui/` + `globals.css` and is designed to be rewritten (see below).
18
+
19
+ ## Blank-canvas mode
20
+
21
+ ```bash
22
+ npm create brainerce-store@latest my-store -- --connection-id vc_xxx --canvas
23
+ ```
24
+
25
+ `--canvas` ships `src/ui/` as bare, semantic, essentially-unstyled skeletons (`DESIGN ME` markers included) with zero aesthetic opinion — commerce stays fully wired. It's the starting point for designing a storefront from scratch with an AI session, and the authoring substrate for new gallery designs. Canvas mode skips the design pack entirely.
26
+
27
+ ## AI-first by default
28
+
29
+ Every scaffolded store is ready to be redesigned by an AI coding session:
30
+
31
+ - **`CLAUDE.md`** — auto-loaded by Claude Code; teaches the session the one rule (`core/` is the platform's, `ui/` is yours) before it touches anything.
32
+ - **`AGENTS.md`** — the same context for other agentic tools.
33
+ - **`/design <your art-direction brief>`** — a ready-made slash command that walks the full redesign: concept → implementation in `ui/` → verification (tsc, real browser, screenshots, RTL checks).
34
+ - **`AI-GUIDE.md`** — the design contract: file map, per-page hook contracts, verification loop, and hard-won RTL/i18n gotchas from real agency builds.
35
+
36
+ ## Architecture (core/ui)
37
+
38
+ - `src/core/` — platform-owned commerce: client, auth, providers, and data/behavior hooks that return state + handlers, never JSX. Don't modify.
39
+ - `src/ui/` — 100% replaceable presentation. Delete-and-rebuild is encouraged; the store keeps working.
40
+ - `src/app/` — thin routes composing the two (~10 lines each).
41
+ - An ESLint boundary rule enforces the split in both directions.
42
+
43
+ Full details: [TEMPLATE-ARCHITECTURE.md](./TEMPLATE-ARCHITECTURE.md).
44
+
45
+ ## Flags
46
+
47
+ | Flag | Description | Default |
48
+ | --- | --- | --- |
49
+ | `--connection-id <id>` | Brainerce vibe-coded connection ID (`vc_*`) | prompted |
50
+ | `--canvas` | Bare unstyled `src/ui/` skeletons for AI-driven design | off |
51
+ | `--language <lang>` | Store language (`en`, `he`) | fetched from store |
52
+ | `--pkg-manager <pm>` | `npm`, `pnpm`, `yarn`, `bun` | auto-detected |
53
+ | `--framework <fw>` | `nextjs` (Vite/Remix coming) | `nextjs` |
54
+ | `--api-url <url>` | Brainerce API base URL (or `BRAINERCE_API_URL` env) | auto-discovered |
55
+ | `--no-git` | Skip git initialization | git on |
56
+ | `--no-install` | Skip dependency installation | install on |
57
+
58
+ Pass `.` as the project name to scaffold into the current directory.
59
+
60
+ ## Requirements
61
+
62
+ Node `^20.19.0 || ^22.13.0 || >=24.0.0`.
63
+
64
+ ## After scaffolding
65
+
66
+ ```bash
67
+ cd my-store
68
+ pnpm dev # store at http://localhost:3000
69
+ ```
70
+
71
+ Want a unique look? Open the folder in Claude Code and run `/design <your art-direction brief>`.
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ var require_package = __commonJS({
31
31
  "package.json"(exports2, module2) {
32
32
  module2.exports = {
33
33
  name: "create-brainerce-store",
34
- version: "1.51.0",
34
+ version: "1.52.1",
35
35
  description: "Scaffold a production-ready e-commerce storefront connected to Brainerce",
36
36
  bin: {
37
37
  "create-brainerce-store": "dist/index.js"
@@ -288,37 +288,6 @@ async function runInteractive(defaults) {
288
288
  initial: 0
289
289
  });
290
290
  }
291
- questions.push({
292
- type: "select",
293
- name: "framework",
294
- message: "Framework:",
295
- choices: [
296
- { title: "Next.js 15 (recommended)", value: "nextjs" },
297
- { title: "Vite + React (coming soon)", value: "vite", disabled: true },
298
- { title: "Remix (coming soon)", value: "remix", disabled: true }
299
- ],
300
- initial: 0
301
- });
302
- if (!defaults.canvas && !defaults.design) {
303
- questions.push({
304
- type: "select",
305
- name: "design",
306
- message: "Design:",
307
- choices: [
308
- {
309
- title: "Passe-Partout \u2014 warm gallery minimal (recommended)",
310
- description: "Framed product cards, placard PDP, print-serif titles",
311
- value: "passepartout"
312
- },
313
- {
314
- title: "Minimal \u2014 bare clean base",
315
- description: "Neutral tokens, unopinionated layout",
316
- value: "minimal"
317
- }
318
- ],
319
- initial: 0
320
- });
321
- }
322
291
  questions.push({
323
292
  type: "select",
324
293
  name: "pkgManager",
@@ -352,9 +321,8 @@ async function runInteractive(defaults) {
352
321
  projectName: defaults.projectName || response.projectName,
353
322
  connectionId: defaults.connectionId || response.connectionId,
354
323
  language: response.language || defaults.language || "en",
355
- framework: response.framework || defaults.framework || "nextjs",
356
- theme: response.theme || defaults.theme || "minimal",
357
- design: response.design || defaults.design || "minimal",
324
+ framework: defaults.framework || "nextjs",
325
+ design: response.design || defaults.design || "atelier",
358
326
  pkgManager: response.pkgManager || defaults.pkgManager || detectInvokingPackageManager()
359
327
  };
360
328
  }
@@ -381,22 +349,8 @@ function toEnvLiteral(value) {
381
349
  function isValidLocale(locale) {
382
350
  return typeof locale === "string" && /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})?$/.test(locale);
383
351
  }
384
- function getFontConfig(language, theme) {
352
+ function getFontConfig(language) {
385
353
  const isHebrew = language === "he";
386
- if (theme === "luxury") {
387
- const subsets = isHebrew ? "['latin']" : "['latin']";
388
- return {
389
- fontImport: "import { Cormorant_Garamond } from 'next/font/google';",
390
- fontVariable: `const font = Cormorant_Garamond({ weight: ['400', '500', '600', '700'], subsets: ${subsets} });`
391
- };
392
- }
393
- if (theme === "playful") {
394
- const subsets = isHebrew ? "['latin']" : "['latin']";
395
- return {
396
- fontImport: "import { Nunito } from 'next/font/google';",
397
- fontVariable: `const font = Nunito({ subsets: ${subsets} });`
398
- };
399
- }
400
354
  if (isHebrew) {
401
355
  return {
402
356
  fontImport: "import { Rubik } from 'next/font/google';",
@@ -409,7 +363,7 @@ function getFontConfig(language, theme) {
409
363
  };
410
364
  }
411
365
  async function scaffold(options) {
412
- const { projectName, framework, theme, scaffoldInPlace } = options;
366
+ const { projectName, framework, scaffoldInPlace } = options;
413
367
  const targetDir = scaffoldInPlace ? process.cwd() : import_path.default.resolve(process.cwd(), projectName);
414
368
  if (!scaffoldInPlace && await import_fs_extra.default.pathExists(targetDir)) {
415
369
  const contents = await import_fs_extra.default.readdir(targetDir);
@@ -419,12 +373,11 @@ async function scaffold(options) {
419
373
  }
420
374
  const templatesRoot = findTemplatesDir(__dirname);
421
375
  const baseDir = import_path.default.join(templatesRoot, framework, "base");
422
- const themeDir = import_path.default.join(templatesRoot, framework, "themes", theme);
423
376
  if (!await import_fs_extra.default.pathExists(baseDir)) {
424
377
  throw new Error(`Template "${framework}" not found at ${baseDir}`);
425
378
  }
426
379
  const direction = getDirection(options.language);
427
- const fontConfig = getFontConfig(options.language, theme);
380
+ const fontConfig = getFontConfig(options.language);
428
381
  const ogLocale = options.language === "he" ? "he_IL" : "en_US";
429
382
  const rawSupportedLocales = options.i18n?.supportedLocales || [options.language];
430
383
  const supportedLocales = rawSupportedLocales.filter(isValidLocale);
@@ -537,16 +490,6 @@ async function scaffold(options) {
537
490
  await import_fs_extra.default.move(import_path.default.join(appDir, entry.name), import_path.default.join(localeDir, entry.name));
538
491
  }
539
492
  }
540
- if (!options.canvas && !designName && await import_fs_extra.default.pathExists(themeDir)) {
541
- const themeCss = import_path.default.join(themeDir, "globals.css");
542
- if (await import_fs_extra.default.pathExists(themeCss)) {
543
- await import_fs_extra.default.copy(themeCss, import_path.default.join(targetDir, "src", "app", "globals.css"));
544
- }
545
- const themeJson = import_path.default.join(themeDir, "theme.json");
546
- if (await import_fs_extra.default.pathExists(themeJson)) {
547
- await import_fs_extra.default.copy(themeJson, import_path.default.join(targetDir, "theme.json"));
548
- }
549
- }
550
493
  }
551
494
  function deepMerge(base, patch) {
552
495
  const out = { ...base };
@@ -777,10 +720,7 @@ var program = new import_commander.Command();
777
720
  program.name("create-brainerce-store").description("Scaffold a production-ready e-commerce storefront connected to Brainerce").version(pkg.version).argument("[project-name]", "Name for the project directory").option("--connection-id <id>", "Brainerce vibe-coded connection ID (vc_*)").option(
778
721
  "--api-url <url>",
779
722
  "Brainerce API base URL (overrides BRAINERCE_API_URL env, defaults to https://api.brainerce.com)"
780
- ).option("--language <lang>", "Store language (en, he)").option("--framework <framework>", "Framework to use", "nextjs").option("--theme <theme>", "Token theme to apply (kept for backward compat)", "minimal").option(
781
- "--design <design>",
782
- "Storefront design pack: passepartout (warm gallery minimal) or minimal (bare base)"
783
- ).option("--pkg-manager <manager>", "Package manager (npm, pnpm, yarn, bun)").option(
723
+ ).option("--language <lang>", "Store language (en, he)").addOption(new import_commander.Option("--framework <framework>", "Framework to use").default("nextjs").hideHelp()).addOption(new import_commander.Option("--design <design>", "Storefront design pack").hideHelp()).option("--pkg-manager <manager>", "Package manager (npm, pnpm, yarn, bun)").option(
784
724
  "--canvas",
785
725
  "Scaffold src/ui as bare unstyled skeletons \u2014 a blank canvas for AI-driven design (commerce stays fully wired)"
786
726
  ).option("--no-git", "Skip git initialization").option("--no-install", "Skip dependency installation").action(async (projectNameArg, options) => {
@@ -814,8 +754,7 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
814
754
  const VALID_LANGUAGES = ["en", "he"];
815
755
  const VALID_PKG_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
816
756
  const VALID_FRAMEWORKS = ["nextjs"];
817
- const VALID_THEMES = ["minimal", "luxury", "playful"];
818
- const VALID_DESIGNS = ["minimal", "passepartout"];
757
+ const VALID_DESIGNS = ["minimal", "atelier"];
819
758
  let language = options.language;
820
759
  if (language && !VALID_LANGUAGES.includes(language)) {
821
760
  logger.error(
@@ -830,11 +769,6 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
830
769
  );
831
770
  process.exit(1);
832
771
  }
833
- let theme = options.theme;
834
- if (!VALID_THEMES.includes(theme)) {
835
- logger.error(`Invalid --theme "${theme}". Expected one of: ${VALID_THEMES.join(", ")}`);
836
- process.exit(1);
837
- }
838
772
  let design = options.design;
839
773
  if (design && !VALID_DESIGNS.includes(design)) {
840
774
  logger.error(`Invalid --design "${design}". Expected one of: ${VALID_DESIGNS.join(", ")}`);
@@ -888,7 +822,6 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
888
822
  connectionId,
889
823
  language: languageDefault,
890
824
  framework,
891
- theme,
892
825
  design,
893
826
  pkgManager,
894
827
  canvas
@@ -897,7 +830,6 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
897
830
  connectionId = answers.connectionId;
898
831
  language = answers.language;
899
832
  framework = answers.framework;
900
- theme = answers.theme;
901
833
  design = answers.design;
902
834
  pkgManager = answers.pkgManager;
903
835
  }
@@ -945,14 +877,13 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
945
877
  connectionId,
946
878
  apiBaseUrl: resolvedApiUrl,
947
879
  framework,
948
- theme,
949
880
  storeName: storeInfo.name,
950
881
  currency: storeInfo.currency,
951
882
  language: language || storeInfo.language,
952
883
  i18n: storeInfo.i18n,
953
884
  scaffoldInPlace,
954
885
  canvas,
955
- design: canvas ? void 0 : design || "minimal"
886
+ design: canvas ? void 0 : design || "atelier"
956
887
  });
957
888
  scaffoldSpinner.succeed(
958
889
  scaffoldInPlace ? "Scaffolded into current directory" : `Scaffolded into ./${projectName}`
@@ -966,9 +897,16 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
966
897
  const gitOpts = { cwd, stdio: ["ignore", "ignore", "pipe"] };
967
898
  execFileSync("git", ["init"], gitOpts);
968
899
  execFileSync("git", ["add", "-A"], gitOpts);
900
+ let hasIdentity = true;
901
+ try {
902
+ execFileSync("git", ["config", "user.email"], gitOpts);
903
+ } catch {
904
+ hasIdentity = false;
905
+ }
906
+ const identityArgs = hasIdentity ? [] : ["-c", "user.name=Brainerce", "-c", "user.email=scaffold@brainerce.com"];
969
907
  execFileSync(
970
908
  "git",
971
- ["commit", "-m", "Initial commit from create-brainerce-store"],
909
+ [...identityArgs, "commit", "-m", "Initial commit from create-brainerce-store"],
972
910
  gitOpts
973
911
  );
974
912
  gitSpinner.succeed("Git initialized");
@@ -981,8 +919,14 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
981
919
  if (!skipInstall) {
982
920
  const installSpinner = createSpinner(`Installing dependencies with ${pkgManager}...`);
983
921
  installSpinner.start();
922
+ const installDir = scaffoldInPlace ? "." : projectName;
984
923
  try {
985
- await installDependencies(scaffoldInPlace ? "." : projectName, pkgManager);
924
+ const installArgs = pkgManager === "pnpm" ? ["--ignore-workspace"] : [];
925
+ await installDependencies(installDir, pkgManager, { args: installArgs });
926
+ const fsExtra = require("fs-extra");
927
+ if (!await fsExtra.pathExists(import_path2.default.join(installDir, "node_modules"))) {
928
+ throw new Error("Install completed but node_modules was not created.");
929
+ }
986
930
  installSpinner.succeed("Dependencies installed");
987
931
  } catch (err) {
988
932
  installSpinner.fail("Dependency installation failed");
package/messages/en.json CHANGED
@@ -100,6 +100,38 @@
100
100
  "addingAll": "Adding...",
101
101
  "by": "By"
102
102
  },
103
+ "reviews": {
104
+ "title": "Reviews",
105
+ "noReviews": "No reviews yet — be the first to share your experience.",
106
+ "verifiedPurchase": "Verified purchase",
107
+ "loading": "Loading…",
108
+ "signIn": "Sign in",
109
+ "signInSuffix": "to leave a review for this product.",
110
+ "onlyPurchasers": "Only customers who purchased this product can leave a review.",
111
+ "reviewsDisabled": "Reviews are not enabled for this store.",
112
+ "cannotReview": "You cannot review this product right now.",
113
+ "confirmDelete": "Delete your review for this product?",
114
+ "deleteFailed": "Could not delete your review. Please try again.",
115
+ "startOver": "Want to start over? You can delete your review.",
116
+ "deleting": "Deleting…",
117
+ "deleteReview": "Delete review",
118
+ "alreadySubmitted": "You've already submitted a review for this product.",
119
+ "tooMany": "Too many submissions. Please try again in a few minutes.",
120
+ "updateFailed": "Could not update your review. Please try again.",
121
+ "submitFailed": "Could not submit your review. Please try again.",
122
+ "thanksUpdated": "Thanks! Your review has been updated.",
123
+ "thanksSubmitted": "Thanks! Your review has been submitted.",
124
+ "editYourReview": "Edit your review",
125
+ "writeReview": "Write a review",
126
+ "yourRating": "Your rating",
127
+ "starRating": "Star rating",
128
+ "yourReview": "Your review",
129
+ "optionalField": "optional",
130
+ "saving": "Saving…",
131
+ "submittingBtn": "Submitting…",
132
+ "saveChanges": "Save changes",
133
+ "submitReview": "Submit review"
134
+ },
103
135
  "customization": {
104
136
  "title": "Personalize this product",
105
137
  "selectPlaceholder": "Choose an option",
package/messages/he.json CHANGED
@@ -100,6 +100,38 @@
100
100
  "addingAll": "מוסיף...",
101
101
  "by": "מאת"
102
102
  },
103
+ "reviews": {
104
+ "title": "ביקורות",
105
+ "noReviews": "אין עדיין ביקורות — היו הראשונים לשתף.",
106
+ "verifiedPurchase": "רכישה מאומתת",
107
+ "loading": "טוען…",
108
+ "signIn": "התחברו",
109
+ "signInSuffix": "כדי לכתוב ביקורת על המוצר.",
110
+ "onlyPurchasers": "רק לקוחות שרכשו את המוצר יכולים לכתוב ביקורת.",
111
+ "reviewsDisabled": "ביקורות אינן פעילות בחנות זו.",
112
+ "cannotReview": "לא ניתן לכתוב ביקורת על המוצר כרגע.",
113
+ "confirmDelete": "למחוק את הביקורת שלך על המוצר?",
114
+ "deleteFailed": "לא ניתן היה למחוק את הביקורת. נסו שוב.",
115
+ "startOver": "רוצים להתחיל מחדש? אפשר למחוק את הביקורת.",
116
+ "deleting": "מוחק…",
117
+ "deleteReview": "מחיקת ביקורת",
118
+ "alreadySubmitted": "כבר שלחתם ביקורת על המוצר הזה.",
119
+ "tooMany": "יותר מדי נסיונות. נסו שוב בעוד כמה דקות.",
120
+ "updateFailed": "לא ניתן היה לעדכן את הביקורת. נסו שוב.",
121
+ "submitFailed": "לא ניתן היה לשלוח את הביקורת. נסו שוב.",
122
+ "thanksUpdated": "תודה! הביקורת עודכנה.",
123
+ "thanksSubmitted": "תודה! הביקורת נשלחה.",
124
+ "editYourReview": "עריכת הביקורת",
125
+ "writeReview": "כתיבת ביקורת",
126
+ "yourRating": "הדירוג שלכם",
127
+ "starRating": "דירוג כוכבים",
128
+ "yourReview": "הביקורת שלכם",
129
+ "optionalField": "לא חובה",
130
+ "saving": "שומר…",
131
+ "submittingBtn": "שולח…",
132
+ "saveChanges": "שמירת שינויים",
133
+ "submitReview": "שליחת ביקורת"
134
+ },
103
135
  "customization": {
104
136
  "title": "התאמה אישית של המוצר",
105
137
  "selectPlaceholder": "בחר אפשרות",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-brainerce-store",
3
- "version": "1.51.0",
3
+ "version": "1.52.1",
4
4
  "description": "Scaffold a production-ready e-commerce storefront connected to Brainerce",
5
5
  "bin": {
6
6
  "create-brainerce-store": "dist/index.js"
@@ -32,6 +32,15 @@ which surface.
32
32
 
33
33
  ## The process
34
34
 
35
+ ## The quality bar (non-negotiable — from the AI-GUIDE)
36
+
37
+ Exactly 3-5 colors (no purple unless asked, no gradients by default), max 2
38
+ font families, tokens-only colors, Tailwind spacing scale, real imagery
39
+ (never abstract filler), content-rich sections, mobile-first. After EACH
40
+ major surface: screenshot → self-critique ("would a Lovable user accept
41
+ this?") → fix → continue. See AI-GUIDE.md "The quality bar".
42
+
43
+
35
44
  1. **Commit to ONE art direction** — write it down in 4 lines (typography
36
45
  pairing incl. a script-compatible webfont, 6-10 color tokens, layout
37
46
  concept, motion language) at the top of `DESIGN.md` in the project root.
@@ -26,10 +26,31 @@ core change, stop and say so instead.
26
26
  | `src/ui/cart/` | you | cart page pieces |
27
27
  | `src/ui/shared/` | you | loader, image wrapper |
28
28
  | `src/app/globals.css` | you | tokens + global styles |
29
+ | `src/components/ui/` | shared | shadcn/ui primitives — compose them, extend via variants |
29
30
  | `src/core/**` | platform | hooks, lib, providers — read, never edit |
30
31
  | `src/components/{checkout,auth,account,seo}` | platform | core-styled in v1; they inherit your tokens |
31
32
  | `src/app/**` | platform | thin routes; edit only to wire new ui components |
32
33
 
34
+ ## The dialect (shadcn/ui + lucide + cn)
35
+
36
+ This store speaks the same component dialect as Lovable / v0 / Bolt output:
37
+
38
+ - **`src/components/ui/` holds official shadcn/ui primitives** (button, card,
39
+ badge, input, label, textarea, select, checkbox, radio-group, separator,
40
+ accordion, dialog, sheet, skeleton, tabs, tooltip). Compose them in `src/ui/`
41
+ instead of hand-rolling controls. Need a new look? **Extend via CVA
42
+ variants** (add a variant to `buttonVariants`/`badgeVariants`), never by
43
+ inline-overriding the same styles in twenty call sites.
44
+ - **Icons: lucide-react only.** No inline `<svg>` paths, no emoji-as-icons,
45
+ no second icon set. Consistent 16/20/24px sizes.
46
+ - **Class merging: `cn()`** from `@/core/lib/utils` (clsx + tailwind-merge) —
47
+ it's the same helper shadcn expects, already wired into every primitive.
48
+ - **Tokens drive everything**: primitives read `--primary`, `--card`,
49
+ `--input`, `--ring`, `--radius`, etc. from `globals.css`. Restyle the store
50
+ by changing tokens (and variants), not by scattering literal colors.
51
+ - `rounded`, `rounded-md`, `rounded-lg` all derive from `--radius`
52
+ (shadcn convention), so corner radius follows the theme automatically.
53
+
33
54
  ## The hook contract (your data supply)
34
55
 
35
56
  UI components get *everything* from `@/core/hooks/*` and
@@ -54,6 +75,34 @@ images, stock) comes from them — **never hardcode products**.
54
75
  4. If the store is RTL: check nothing is left-anchored that should be
55
76
  right-anchored, and directional arrows point with the reading direction.
56
77
 
78
+ ## The quality bar (distilled from Lovable / v0 / Bolt system prompts)
79
+
80
+ Beautiful is the top priority — the first render must wow. Hard rules:
81
+
82
+ 1. **Design system first**: define all HSL semantic tokens in globals.css
83
+ BEFORE styling any component. Never direct colors (`text-white`,
84
+ `bg-black`) in classNames — tokens only.
85
+ 2. **Color budget: exactly 3-5 colors.** 1 brand color, 2-3 neutrals, 1-2
86
+ accents. Never purple/violet unless the merchant asked. No gradients by
87
+ default — solid colors; gradients only as subtle accents if requested.
88
+ 3. **Max 2 font families** (1 display + 1 body, both with the store's
89
+ script). Body line-height 1.4-1.6. Nothing below 14px.
90
+ 4. **Mobile-first**; flexbox by default, grid for true 2D; no absolute
91
+ positioning unless necessary.
92
+ 5. **Tailwind discipline**: spacing scale only (`p-4`, never `p-[16px]`),
93
+ `gap-*` over margins between siblings, `text-balance` on headlines.
94
+ 6. **Real imagery everywhere** — product photos from the catalog do the
95
+ heavy lifting; free stock hotlinks (Pexels/Unsplash) for editorial
96
+ sections. NEVER abstract filler shapes (gradient circles, blobs).
97
+ NEVER emojis as icons — one icon set, consistent 16/20/24px sizes.
98
+ 7. **Content-rich**: no section may render empty or thin. Empty states are
99
+ designed states with copy and structure, not blank space.
100
+ 8. Component variants in the design system, not inline overrides.
101
+ 9. Semantic HTML + ARIA + alt text + `sr-only` labels — always.
102
+ 10. **Verify with your eyes**: screenshot after each major surface, critique
103
+ it ("would a Lovable user accept this?"), fix, and only then move on.
104
+
105
+
57
106
  ## Hard-won gotchas (each one cost a real debugging session)
58
107
 
59
108
  - **RTL + cloned images**: `next/image` renders its `<img>` with `inset: 0`.
@@ -62,9 +111,9 @@ images, stock) comes from them — **never hardcode products**.
62
111
  Set `inset: 'auto'` before positioning.
63
112
  - **Never name a custom class `overline`** — it is a Tailwind utility
64
113
  (`text-decoration-line: overline`) and will draw a line above your text.
65
- - **`rounded-md` / `rounded-lg` are fixed radii** — they ignore your
66
- `--radius` token. For token-driven corners use `rounded` (DEFAULT) or set
67
- radii explicitly.
114
+ - **`rounded` / `rounded-md` / `rounded-lg` all follow `--radius`** (shadcn
115
+ convention, wired in tailwind.config.ts) change the token, not the
116
+ classes, when you want sharper or softer corners.
68
117
  - **Hebrew has no uppercase** — remove `text-transform: uppercase` and wide
69
118
  `letter-spacing` from heading styles; they are Latin idioms that distort
70
119
  Hebrew (tracking is acceptable only at caption sizes).
@@ -21,6 +21,16 @@ and handlers, never JSX. Never hardcode catalog content.
21
21
  contracts, and hard-won RTL/i18n gotchas that will save you real debugging
22
22
  time.
23
23
 
24
+ ## The dialect
25
+
26
+ - `src/components/ui/` = official **shadcn/ui primitives** (Button, Card,
27
+ Badge, Input, Select, Accordion, Dialog, Sheet, Skeleton, …). Compose them;
28
+ extend looks via CVA **variants**, never repeated inline overrides.
29
+ - Icons: **lucide-react only** — no inline `<svg>`, no emoji-as-icons.
30
+ - Class merging: **`cn()`** from `@/core/lib/utils`.
31
+ - Colors/radius come from the semantic HSL tokens in `globals.css`
32
+ (`--primary`, `--card`, `--ring`, `--radius`, …) — restyle via tokens.
33
+
24
34
  ## Redesigning? Use the ready-made flow
25
35
 
26
36
  Run `/design <your art-direction brief>` — it walks the whole process:
@@ -1,39 +1,52 @@
1
- {
2
- "name": "<%= projectName %>",
3
- "version": "0.1.0",
4
- "private": true,
5
- "scripts": {
6
- "dev": "next dev",
7
- "build": "next build",
8
- "start": "next start",
9
- "lint": "next lint",
10
- "setup": "node scripts/fetch-store-info.mjs"
11
- },
12
- "dependencies": {
13
- "brainerce": "<%= brainerceVersion %>",
14
- "next": "^15.3.4",
15
- "react": "^19.0.0",
16
- "react-dom": "^19.0.0",
17
- "clsx": "^2.1.0",
18
- "tailwind-merge": "^2.2.0",
19
- "isomorphic-dompurify": "<%= isomorphicDompurifyVersion %>",
20
- "sharp": "^0.35.3"
21
- },
22
- "devDependencies": {
23
- "@types/node": "^20.0.0",
24
- "@types/react": "^19.0.0",
25
- "@types/react-dom": "^19.0.0",
26
- "autoprefixer": "^10.4.0",
27
- "eslint": "^9.0.0",
28
- "eslint-config-next": "^15.3.4",
29
- "postcss": "^8.4.49",
30
- "tailwindcss": "^3.4.0",
31
- "typescript": "^5.4.0"
32
- },
33
- "engines": {
34
- "node": "^20.19.0 || ^22.13.0 || >=24.0.0"
35
- },
36
- "pnpm": {
37
- "onlyBuiltDependencies": ["sharp"]
38
- }
39
- }
1
+ {
2
+ "name": "<%= projectName %>",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "next lint",
10
+ "setup": "node scripts/fetch-store-info.mjs"
11
+ },
12
+ "dependencies": {
13
+ "brainerce": "<%= brainerceVersion %>",
14
+ "next": "^15.3.4",
15
+ "react": "^19.0.0",
16
+ "react-dom": "^19.0.0",
17
+ "@radix-ui/react-accordion": "^1.2.0",
18
+ "@radix-ui/react-checkbox": "^1.1.1",
19
+ "@radix-ui/react-dialog": "^1.1.2",
20
+ "@radix-ui/react-label": "^2.1.0",
21
+ "@radix-ui/react-radio-group": "^1.2.0",
22
+ "@radix-ui/react-select": "^2.1.1",
23
+ "@radix-ui/react-separator": "^1.1.0",
24
+ "@radix-ui/react-slot": "^1.1.0",
25
+ "@radix-ui/react-tabs": "^1.1.0",
26
+ "@radix-ui/react-tooltip": "^1.1.4",
27
+ "class-variance-authority": "^0.7.1",
28
+ "clsx": "^2.1.1",
29
+ "lucide-react": "^0.462.0",
30
+ "tailwind-merge": "^2.5.2",
31
+ "tailwindcss-animate": "^1.0.7",
32
+ "isomorphic-dompurify": "<%= isomorphicDompurifyVersion %>",
33
+ "sharp": "^0.35.3"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^20.0.0",
37
+ "@types/react": "^19.0.0",
38
+ "@types/react-dom": "^19.0.0",
39
+ "autoprefixer": "^10.4.0",
40
+ "eslint": "^9.0.0",
41
+ "eslint-config-next": "^15.3.4",
42
+ "postcss": "^8.4.49",
43
+ "tailwindcss": "^3.4.0",
44
+ "typescript": "^5.4.0"
45
+ },
46
+ "engines": {
47
+ "node": "^20.19.0 || ^22.13.0 || >=24.0.0"
48
+ },
49
+ "pnpm": {
50
+ "onlyBuiltDependencies": ["sharp"]
51
+ }
52
+ }
@@ -1,30 +1,36 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
4
-
5
- @layer base {
6
- :root {
7
- --background: 0 0% 100%;
8
- --foreground: 0 0% 9%;
9
- --primary: 0 0% 9%;
10
- --primary-foreground: 0 0% 98%;
11
- --secondary: 0 0% 96%;
12
- --secondary-foreground: 0 0% 9%;
13
- --muted: 0 0% 96%;
14
- --muted-foreground: 0 0% 45%;
15
- --accent: 0 0% 96%;
16
- --accent-foreground: 0 0% 9%;
17
- --destructive: 0 84% 60%;
18
- --destructive-foreground: 0 0% 98%;
19
- --border: 0 0% 90%;
20
- --radius: 0.5rem;
21
- }
22
-
23
- * {
24
- @apply border-border;
25
- }
26
-
27
- body {
28
- @apply bg-background text-foreground antialiased;
29
- }
30
- }
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 0 0% 100%;
8
+ --foreground: 0 0% 9%;
9
+ --primary: 0 0% 9%;
10
+ --primary-foreground: 0 0% 98%;
11
+ --secondary: 0 0% 96%;
12
+ --secondary-foreground: 0 0% 9%;
13
+ --muted: 0 0% 96%;
14
+ --muted-foreground: 0 0% 45%;
15
+ --accent: 0 0% 96%;
16
+ --accent-foreground: 0 0% 9%;
17
+ --destructive: 0 84% 60%;
18
+ --destructive-foreground: 0 0% 98%;
19
+ --border: 0 0% 90%;
20
+ --input: 0 0% 90%;
21
+ --ring: 0 0% 9%;
22
+ --card: 0 0% 100%;
23
+ --card-foreground: 0 0% 9%;
24
+ --popover: 0 0% 100%;
25
+ --popover-foreground: 0 0% 9%;
26
+ --radius: 0.5rem;
27
+ }
28
+
29
+ * {
30
+ @apply border-border;
31
+ }
32
+
33
+ body {
34
+ @apply bg-background text-foreground antialiased;
35
+ }
36
+ }