create-brainerce-store 1.50.5 → 1.52.0

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 (230) hide show
  1. package/README.md +72 -0
  2. package/dist/index.js +146 -100
  3. package/messages/en.json +36 -1
  4. package/messages/he.json +36 -1
  5. package/package.json +1 -1
  6. package/templates/nextjs/base/.claude/commands/design.md +60 -0
  7. package/templates/nextjs/base/.env.local.ejs +5 -0
  8. package/templates/nextjs/base/.eslintrc.json +57 -3
  9. package/templates/nextjs/base/AGENTS.md +41 -0
  10. package/templates/nextjs/base/AI-GUIDE.md +143 -0
  11. package/templates/nextjs/base/CLAUDE.md +52 -0
  12. package/templates/nextjs/base/TRANSLATIONS.md +1 -1
  13. package/templates/nextjs/base/next.config.ts +2 -2
  14. package/templates/nextjs/base/package.json.ejs +52 -39
  15. package/templates/nextjs/base/src/app/account/page.tsx +5 -5
  16. package/templates/nextjs/base/src/app/api/auth/logout/route.ts +1 -1
  17. package/templates/nextjs/base/src/app/api/auth/reset-password/route.ts +2 -2
  18. package/templates/nextjs/base/src/app/api/store/[...path]/route.ts +1 -1
  19. package/templates/nextjs/base/src/app/auth/callback/page.tsx +4 -4
  20. package/templates/nextjs/base/src/app/blog/[slug]/page.tsx.ejs +4 -4
  21. package/templates/nextjs/base/src/app/blog/page.tsx.ejs +2 -2
  22. package/templates/nextjs/base/src/app/cart/page.tsx +2 -173
  23. package/templates/nextjs/base/src/app/checkout/page.tsx +12 -11
  24. package/templates/nextjs/base/src/app/contact/page.tsx +3 -3
  25. package/templates/nextjs/base/src/app/faq/page.tsx.ejs +2 -2
  26. package/templates/nextjs/base/src/app/forgot-password/page.tsx +4 -4
  27. package/templates/nextjs/base/src/app/globals.css +36 -30
  28. package/templates/nextjs/base/src/app/layout.tsx.ejs +12 -12
  29. package/templates/nextjs/base/src/app/login/page.tsx +4 -4
  30. package/templates/nextjs/base/src/app/order-confirmation/page.tsx +19 -12
  31. package/templates/nextjs/base/src/app/page.tsx +4 -4
  32. package/templates/nextjs/base/src/app/pages/[slug]/page.tsx.ejs +3 -3
  33. package/templates/nextjs/base/src/app/payment-complete/page.tsx +1 -1
  34. package/templates/nextjs/base/src/app/products/[slug]/page.tsx +6 -6
  35. package/templates/nextjs/base/src/app/products/page.tsx +4 -623
  36. package/templates/nextjs/base/src/app/register/page.tsx +4 -4
  37. package/templates/nextjs/base/src/app/reset-password/page.tsx +5 -5
  38. package/templates/nextjs/base/src/app/sitemap.ts +1 -1
  39. package/templates/nextjs/base/src/app/verify-email/page.tsx +5 -5
  40. package/templates/nextjs/base/src/components/account/address-book.tsx +3 -3
  41. package/templates/nextjs/base/src/components/account/order-customizations.tsx +3 -3
  42. package/templates/nextjs/base/src/components/account/order-history.tsx +13 -5
  43. package/templates/nextjs/base/src/components/account/order-payment-block.tsx +2 -2
  44. package/templates/nextjs/base/src/components/account/order-shipping-block.tsx +2 -2
  45. package/templates/nextjs/base/src/components/account/order-status-timeline.tsx +2 -2
  46. package/templates/nextjs/base/src/components/account/profile-section.tsx +3 -3
  47. package/templates/nextjs/base/src/components/auth/login-form.tsx +4 -4
  48. package/templates/nextjs/base/src/components/auth/oauth-buttons.tsx +4 -4
  49. package/templates/nextjs/base/src/components/auth/register-form.tsx +4 -4
  50. package/templates/nextjs/base/src/components/brainerce-bot.tsx +2 -2
  51. package/templates/nextjs/base/src/components/checkout/checkout-form.tsx +24 -3
  52. package/templates/nextjs/base/src/components/checkout/custom-fields-step.tsx +2 -2
  53. package/templates/nextjs/base/src/components/checkout/delivery-method-step.tsx +2 -2
  54. package/templates/nextjs/base/src/components/checkout/order-bump-card.tsx +4 -4
  55. package/templates/nextjs/base/src/components/checkout/payment-step.tsx +20 -16
  56. package/templates/nextjs/base/src/components/checkout/pickup-step.tsx +3 -3
  57. package/templates/nextjs/base/src/components/checkout/shipping-step.tsx +3 -3
  58. package/templates/nextjs/base/src/components/checkout/tax-display.tsx +3 -3
  59. package/templates/nextjs/base/src/components/seo/organization-json-ld.tsx +2 -2
  60. package/templates/nextjs/base/src/components/seo/product-json-ld.tsx +3 -3
  61. package/templates/nextjs/base/src/components/ui/accordion.tsx +53 -0
  62. package/templates/nextjs/base/src/components/ui/badge.tsx +32 -0
  63. package/templates/nextjs/base/src/components/ui/button.tsx +49 -0
  64. package/templates/nextjs/base/src/components/ui/card.tsx +55 -0
  65. package/templates/nextjs/base/src/components/ui/checkbox.tsx +28 -0
  66. package/templates/nextjs/base/src/components/ui/dialog.tsx +107 -0
  67. package/templates/nextjs/base/src/components/ui/input.tsx +22 -0
  68. package/templates/nextjs/base/src/components/ui/label.tsx +21 -0
  69. package/templates/nextjs/base/src/components/ui/radio-group.tsx +38 -0
  70. package/templates/nextjs/base/src/components/ui/select.tsx +153 -0
  71. package/templates/nextjs/base/src/components/ui/separator.tsx +26 -0
  72. package/templates/nextjs/base/src/components/ui/sheet.tsx +125 -0
  73. package/templates/nextjs/base/src/components/ui/skeleton.tsx +7 -0
  74. package/templates/nextjs/base/src/components/ui/tabs.tsx +55 -0
  75. package/templates/nextjs/base/src/components/ui/textarea.tsx +21 -0
  76. package/templates/nextjs/base/src/components/ui/tooltip.tsx +32 -0
  77. package/templates/nextjs/base/src/core/hooks/use-cart-page.ts +58 -0
  78. package/templates/nextjs/base/src/core/hooks/use-home-data.ts +51 -0
  79. package/templates/nextjs/base/src/core/hooks/use-product-listing.ts +295 -0
  80. package/templates/nextjs/base/src/core/hooks/use-product-page.ts +278 -0
  81. package/templates/nextjs/base/src/{hooks → core/hooks}/use-search.ts +1 -1
  82. package/templates/nextjs/base/src/{lib → core/lib}/brainerce.ts.ejs +1 -1
  83. package/templates/nextjs/base/src/core/lib/product-options.ts +121 -0
  84. package/templates/nextjs/base/src/{lib → core/lib}/resolve-currency.ts +1 -1
  85. package/templates/nextjs/base/src/{lib → core/lib}/safe-redirect.ts +1 -1
  86. package/templates/nextjs/base/src/{lib → core/lib}/sanitize.ts.ejs +1 -1
  87. package/templates/nextjs/base/src/{lib → core/lib}/use-currency.ts +1 -1
  88. package/templates/nextjs/base/src/{providers → core/providers}/store-provider.tsx.ejs +4 -4
  89. package/templates/nextjs/base/src/{components → ui}/cart/cart-bundle-offer.tsx +22 -16
  90. package/templates/nextjs/base/src/{components → ui}/cart/cart-item.tsx +8 -14
  91. package/templates/nextjs/base/src/{components → ui}/cart/cart-nudges.tsx +28 -39
  92. package/templates/nextjs/base/src/{components → ui}/cart/cart-summary.tsx +7 -5
  93. package/templates/nextjs/base/src/{components → ui}/cart/cart-upgrade-banner.tsx +13 -28
  94. package/templates/nextjs/base/src/ui/cart/cart-view.tsx +140 -0
  95. package/templates/nextjs/base/src/{components → ui}/cart/coupon-input.tsx +14 -25
  96. package/templates/nextjs/base/src/{components → ui}/cart/free-shipping-bar.tsx +6 -7
  97. package/templates/nextjs/base/src/{components → ui}/cart/reservation-countdown.tsx +95 -103
  98. package/templates/nextjs/base/src/ui/home/discount-banner-strip.tsx +20 -0
  99. package/templates/nextjs/base/src/ui/home/featured-products-section.tsx +24 -0
  100. package/templates/nextjs/base/src/ui/home/hero-section.tsx +27 -0
  101. package/templates/nextjs/base/src/ui/home/home-client.tsx +29 -0
  102. package/templates/nextjs/base/src/{components/content → ui/layout}/announcement-bar.tsx.ejs +116 -125
  103. package/templates/nextjs/base/src/ui/layout/faq-section.tsx.ejs +90 -0
  104. package/templates/nextjs/base/src/{components/content → ui/layout}/header-account.tsx +5 -20
  105. package/templates/nextjs/base/src/ui/layout/language-switcher.tsx.ejs +80 -0
  106. package/templates/nextjs/base/src/{components/content → ui/layout}/rich-text-block.tsx.ejs +1 -1
  107. package/templates/nextjs/base/src/{components/content → ui/layout}/site-footer.tsx.ejs +144 -164
  108. package/templates/nextjs/base/src/{components/content → ui/layout}/site-header.tsx.ejs +152 -182
  109. package/templates/nextjs/base/src/{components/products → ui/product}/customization-fields.tsx +457 -478
  110. package/templates/nextjs/base/src/{components/products → ui/product}/discount-badge.tsx +18 -22
  111. package/templates/nextjs/base/src/{components/products → ui/product}/frequently-bought-together.tsx +21 -33
  112. package/templates/nextjs/base/src/ui/product/modifier-group-selector.tsx +206 -0
  113. package/templates/nextjs/base/src/{components/shared → ui/product}/price-display.tsx +5 -4
  114. package/templates/nextjs/base/src/{components/products → ui/product}/product-card.tsx +238 -271
  115. package/templates/nextjs/base/src/{app/products/[slug] → ui/product}/product-client-section.tsx +455 -631
  116. package/templates/nextjs/base/src/{components/products → ui/product}/product-grid.tsx +3 -3
  117. package/templates/nextjs/base/src/ui/product/product-listing.tsx +446 -0
  118. package/templates/nextjs/base/src/{components/products → ui/product}/recommendation-section.tsx +102 -107
  119. package/templates/nextjs/base/src/{components/reviews → ui/product}/review-form.tsx +46 -45
  120. package/templates/nextjs/base/src/{components/reviews/reviews-section.tsx → ui/product/reviews-section.tsx.ejs} +38 -15
  121. package/templates/nextjs/base/src/{components/products → ui/product}/stock-badge.tsx +61 -63
  122. package/templates/nextjs/base/src/{components/products → ui/product}/variant-selector.tsx +3 -3
  123. package/templates/nextjs/base/src/{components → ui}/shared/cdn-image.tsx +1 -1
  124. package/templates/nextjs/base/src/{components → ui}/shared/loading-spinner.tsx +2 -2
  125. package/templates/nextjs/base/tailwind.config.ts +69 -30
  126. package/templates/nextjs/designs/atelier/app-overlay/layout.tsx.ejs +251 -0
  127. package/templates/nextjs/designs/atelier/globals.css +396 -0
  128. package/templates/nextjs/designs/atelier/messages-patch/en.json +99 -0
  129. package/templates/nextjs/designs/atelier/messages-patch/he.json +99 -0
  130. package/templates/nextjs/designs/atelier/ui/cart/cart-bundle-offer.tsx +110 -0
  131. package/templates/nextjs/designs/atelier/ui/cart/cart-drawer.tsx +163 -0
  132. package/templates/nextjs/designs/atelier/ui/cart/cart-item.tsx +140 -0
  133. package/templates/nextjs/designs/atelier/ui/cart/cart-nudges.tsx +34 -0
  134. package/templates/nextjs/designs/atelier/ui/cart/cart-summary.tsx +107 -0
  135. package/templates/nextjs/designs/atelier/ui/cart/cart-upgrade-banner.tsx +123 -0
  136. package/templates/nextjs/designs/atelier/ui/cart/cart-view.tsx +147 -0
  137. package/templates/nextjs/designs/atelier/ui/cart/coupon-input.tsx +142 -0
  138. package/templates/nextjs/designs/atelier/ui/cart/free-shipping-bar.tsx +77 -0
  139. package/templates/nextjs/designs/atelier/ui/cart/reservation-countdown.tsx +89 -0
  140. package/templates/nextjs/designs/atelier/ui/home/benefits-band.tsx +34 -0
  141. package/templates/nextjs/designs/atelier/ui/home/category-tiles.tsx +148 -0
  142. package/templates/nextjs/designs/atelier/ui/home/discount-banner-strip.tsx +27 -0
  143. package/templates/nextjs/designs/atelier/ui/home/editorial-band.tsx +73 -0
  144. package/templates/nextjs/designs/atelier/ui/home/featured-products-section.tsx +36 -0
  145. package/templates/nextjs/designs/atelier/ui/home/hero-section.tsx +148 -0
  146. package/templates/nextjs/designs/atelier/ui/home/home-client.tsx +54 -0
  147. package/templates/nextjs/designs/atelier/ui/home/newsletter-section.tsx +78 -0
  148. package/templates/nextjs/designs/atelier/ui/home/testimonials-band.tsx +46 -0
  149. package/templates/nextjs/designs/atelier/ui/layout/announcement-bar.tsx +118 -0
  150. package/templates/nextjs/designs/atelier/ui/layout/faq-section.tsx +96 -0
  151. package/templates/nextjs/designs/atelier/ui/layout/header-account.tsx +36 -0
  152. package/templates/nextjs/designs/atelier/ui/layout/header-cart.tsx +36 -0
  153. package/templates/nextjs/designs/atelier/ui/layout/language-switcher.tsx.ejs +137 -0
  154. package/templates/nextjs/designs/atelier/ui/layout/nav-url.ts +14 -0
  155. package/templates/nextjs/designs/atelier/ui/layout/rich-text-block.tsx +34 -0
  156. package/templates/nextjs/designs/atelier/ui/layout/site-footer.tsx.ejs +141 -0
  157. package/templates/nextjs/designs/atelier/ui/layout/site-header.tsx.ejs +138 -0
  158. package/templates/nextjs/designs/atelier/ui/product/customization-fields.tsx +466 -0
  159. package/templates/nextjs/designs/atelier/ui/product/discount-badge.tsx +17 -0
  160. package/templates/nextjs/designs/atelier/ui/product/frequently-bought-together.tsx +196 -0
  161. package/templates/nextjs/designs/atelier/ui/product/modifier-group-selector.tsx +193 -0
  162. package/templates/nextjs/designs/atelier/ui/product/price-display.tsx +69 -0
  163. package/templates/nextjs/designs/atelier/ui/product/product-card.tsx +260 -0
  164. package/templates/nextjs/designs/atelier/ui/product/product-client-section.tsx +471 -0
  165. package/templates/nextjs/designs/atelier/ui/product/product-grid.tsx +47 -0
  166. package/templates/nextjs/designs/atelier/ui/product/product-listing.tsx +260 -0
  167. package/templates/nextjs/designs/atelier/ui/product/recommendation-section.tsx +95 -0
  168. package/templates/nextjs/designs/atelier/ui/product/review-form.tsx +267 -0
  169. package/templates/nextjs/designs/atelier/ui/product/reviews-section.tsx.ejs +148 -0
  170. package/templates/nextjs/designs/atelier/ui/product/stock-badge.tsx +66 -0
  171. package/templates/nextjs/designs/atelier/ui/product/variant-selector.tsx +206 -0
  172. package/templates/nextjs/designs/atelier/ui/shared/cdn-image.tsx +29 -0
  173. package/templates/nextjs/designs/atelier/ui/shared/fly-to-cart.ts +86 -0
  174. package/templates/nextjs/designs/atelier/ui/shared/icons.tsx +269 -0
  175. package/templates/nextjs/designs/atelier/ui/shared/loading-spinner.tsx +64 -0
  176. package/templates/nextjs/designs/atelier/ui/shared/reveal.tsx +71 -0
  177. package/templates/nextjs/designs/atelier/ui/shared/select-menu.tsx +125 -0
  178. package/templates/nextjs/themes/luxury/globals.css +405 -399
  179. package/templates/nextjs/themes/minimal/globals.css +36 -30
  180. package/templates/nextjs/themes/playful/globals.css +406 -400
  181. package/templates/nextjs/ui-canvas/cart/cart-bundle-offer.tsx +89 -0
  182. package/templates/nextjs/ui-canvas/cart/cart-item.tsx +123 -0
  183. package/templates/nextjs/ui-canvas/cart/cart-nudges.tsx +27 -0
  184. package/templates/nextjs/ui-canvas/cart/cart-summary.tsx +99 -0
  185. package/templates/nextjs/ui-canvas/cart/cart-upgrade-banner.tsx +105 -0
  186. package/templates/nextjs/ui-canvas/cart/cart-view.tsx +106 -0
  187. package/templates/nextjs/ui-canvas/cart/coupon-input.tsx +119 -0
  188. package/templates/nextjs/ui-canvas/cart/free-shipping-bar.tsx +54 -0
  189. package/templates/nextjs/ui-canvas/cart/reservation-countdown.tsx +81 -0
  190. package/templates/nextjs/ui-canvas/home/discount-banner-strip.tsx +19 -0
  191. package/templates/nextjs/ui-canvas/home/featured-products-section.tsx +23 -0
  192. package/templates/nextjs/ui-canvas/home/hero-section.tsx +21 -0
  193. package/templates/nextjs/ui-canvas/home/home-client.tsx +26 -0
  194. package/templates/nextjs/ui-canvas/layout/announcement-bar.tsx.ejs +101 -0
  195. package/templates/nextjs/ui-canvas/layout/faq-section.tsx.ejs +71 -0
  196. package/templates/nextjs/ui-canvas/layout/header-account.tsx +31 -0
  197. package/templates/nextjs/{base/src/components → ui-canvas}/layout/language-switcher.tsx.ejs +76 -70
  198. package/templates/nextjs/ui-canvas/layout/rich-text-block.tsx.ejs +36 -0
  199. package/templates/nextjs/ui-canvas/layout/site-footer.tsx.ejs +82 -0
  200. package/templates/nextjs/ui-canvas/layout/site-header.tsx.ejs +119 -0
  201. package/templates/nextjs/ui-canvas/product/customization-fields.tsx +445 -0
  202. package/templates/nextjs/ui-canvas/product/discount-badge.tsx +19 -0
  203. package/templates/nextjs/ui-canvas/product/frequently-bought-together.tsx +168 -0
  204. package/templates/nextjs/ui-canvas/product/modifier-group-selector.tsx +165 -0
  205. package/templates/nextjs/ui-canvas/product/price-display.tsx +52 -0
  206. package/templates/nextjs/ui-canvas/product/product-card.tsx +197 -0
  207. package/templates/nextjs/ui-canvas/product/product-client-section.tsx +352 -0
  208. package/templates/nextjs/ui-canvas/product/product-grid.tsx +27 -0
  209. package/templates/nextjs/ui-canvas/product/product-listing.tsx +224 -0
  210. package/templates/nextjs/ui-canvas/product/recommendation-section.tsx +99 -0
  211. package/templates/nextjs/ui-canvas/product/review-form.tsx +266 -0
  212. package/templates/nextjs/ui-canvas/product/reviews-section.tsx.ejs +96 -0
  213. package/templates/nextjs/ui-canvas/product/stock-badge.tsx +45 -0
  214. package/templates/nextjs/ui-canvas/product/variant-selector.tsx +212 -0
  215. package/templates/nextjs/ui-canvas/shared/cdn-image.tsx +31 -0
  216. package/templates/nextjs/ui-canvas/shared/loading-spinner.tsx +27 -0
  217. package/templates/nextjs/base/src/app/home-client.tsx +0 -98
  218. package/templates/nextjs/base/src/components/content/faq-section.tsx.ejs +0 -103
  219. package/templates/nextjs/base/src/components/products/modifier-group-selector.tsx +0 -238
  220. /package/templates/nextjs/base/src/{lib → core/lib}/auth.ts +0 -0
  221. /package/templates/nextjs/base/src/{lib → core/lib}/csrf.ts +0 -0
  222. /package/templates/nextjs/base/src/{lib → core/lib}/image-hosts.ts +0 -0
  223. /package/templates/nextjs/base/src/{lib → core/lib}/navigation.tsx.ejs +0 -0
  224. /package/templates/nextjs/base/src/{lib → core/lib}/nonce.ts +0 -0
  225. /package/templates/nextjs/base/src/{lib → core/lib}/sanitize-html.ts +0 -0
  226. /package/templates/nextjs/base/src/{lib → core/lib}/seo.ts +0 -0
  227. /package/templates/nextjs/base/src/{lib → core/lib}/store-info.ts +0 -0
  228. /package/templates/nextjs/base/src/{lib → core/lib}/translations.ts.ejs +0 -0
  229. /package/templates/nextjs/base/src/{lib → core/lib}/utils.ts +0 -0
  230. /package/templates/nextjs/base/src/{lib → core/lib}/validation.ts +0 -0
@@ -1,3 +1,57 @@
1
- {
2
- "extends": ["next/core-web-vitals"]
3
- }
1
+ {
2
+ "extends": [
3
+ "next/core-web-vitals"
4
+ ],
5
+ "overrides": [
6
+ {
7
+ "files": [
8
+ "src/ui/**/*.{ts,tsx}"
9
+ ],
10
+ "rules": {
11
+ "no-restricted-imports": [
12
+ "error",
13
+ {
14
+ "patterns": [
15
+ {
16
+ "group": [
17
+ "@/core/lib/*",
18
+ "!@/core/lib/auth",
19
+ "!@/core/lib/brainerce",
20
+ "!@/core/lib/image-hosts",
21
+ "!@/core/lib/navigation",
22
+ "!@/core/lib/product-options",
23
+ "!@/core/lib/sanitize",
24
+ "!@/core/lib/sanitize-html",
25
+ "!@/core/lib/translations",
26
+ "!@/core/lib/use-currency",
27
+ "!@/core/lib/utils"
28
+ ],
29
+ "message": "UI consumes data via @/core/hooks/* and @/core/providers/* — not core internals. (Approved presentation helpers are exempt.)"
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ }
35
+ },
36
+ {
37
+ "files": [
38
+ "src/core/**/*.{ts,tsx}"
39
+ ],
40
+ "rules": {
41
+ "no-restricted-imports": [
42
+ "error",
43
+ {
44
+ "patterns": [
45
+ {
46
+ "group": [
47
+ "@/ui/*"
48
+ ],
49
+ "message": "core/ must never depend on presentation (ui/)."
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ }
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,41 @@
1
+ # AGENTS.md — this is a Brainerce storefront
2
+
3
+ This store's commerce engine (cart, checkout, variants, auth, i18n) is
4
+ already wired and working. Your job here is almost always **design**.
5
+
6
+ ## The one rule
7
+
8
+ **`src/core/` is the platform's. `src/ui/` is yours.**
9
+
10
+ The shipped `src/ui/` is a working reference, not a design to preserve —
11
+ full delete-and-rebuild of ui files is encouraged and expected.
12
+ Rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
13
+ like — the store keeps working. Never modify `src/core/`, `src/app/api/`, or
14
+ the checkout/auth/account components. Data and behavior come exclusively from
15
+ `@/core/hooks/*` and `@/core/providers/store-provider` — hooks return state
16
+ and handlers, never JSX. Never hardcode catalog content.
17
+
18
+ **Read `AI-GUIDE.md` before any redesign** — it has the full file map, hook
19
+ contracts, and hard-won RTL/i18n gotchas that will save you real debugging
20
+ time.
21
+
22
+ ## Redesigning?
23
+
24
+ Follow the process documented in AI-GUIDE.md: commit to one art direction,
25
+ rewrite tokens first, then surfaces in order (header, home, card, product
26
+ page, cart), then verify.
27
+
28
+ ## Verify before declaring done
29
+
30
+ 1. `pnpm exec tsc --noEmit` → 0 errors
31
+ 2. `pnpm dev` → drive the changed flow in a real browser (home → product →
32
+ add to cart → cart)
33
+ 3. Screenshot desktop (1440px) and mobile (390px)
34
+ 4. RTL stores: check anchoring and arrow directions
35
+
36
+ ## i18n
37
+
38
+ Every user-facing string goes through `useTranslations()` with keys in **all**
39
+ files under `messages/`. Hebrew: no uppercase transforms, no wide
40
+ letter-spacing on headings, logical CSS properties only (`ms-/me-`, `ps-/pe-`,
41
+ `start-/end-`).
@@ -0,0 +1,143 @@
1
+ # AI-GUIDE — designing this store safely
2
+
3
+ You (an AI coding assistant, or a human designer) have been asked to redesign
4
+ this storefront. This guide is the contract that lets you go as bold as you
5
+ want without breaking commerce. It was distilled from real agency builds.
6
+
7
+ ## The one rule
8
+
9
+ **`src/core/` is the platform's. `src/ui/` is yours.**
10
+
11
+ Everything under `src/ui/` may be rewritten from scratch — layouts, markup,
12
+ classes, animations, entire visual languages. (Canvas-mode stores —
13
+ scaffolded with `--canvas` — ship `src/ui/` as bare unstyled skeletons with
14
+ `DESIGN ME` markers; same rules apply, you're just starting from zero.) Everything under `src/core/`
15
+ (and `src/app/api/`) keeps the store working: cart, checkout, variants,
16
+ inventory, auth, SEO, i18n. Never modify it. If a redesign seems to require a
17
+ core change, stop and say so instead.
18
+
19
+ ## File map
20
+
21
+ | Path | Owner | Notes |
22
+ |------|-------|-------|
23
+ | `src/ui/layout/` | you | header, footer, announcement bar |
24
+ | `src/ui/home/` | you | homepage sections |
25
+ | `src/ui/product/` | you | card, grid, listing, product page, price, badges, selectors |
26
+ | `src/ui/cart/` | you | cart page pieces |
27
+ | `src/ui/shared/` | you | loader, image wrapper |
28
+ | `src/app/globals.css` | you | tokens + global styles |
29
+ | `src/components/ui/` | shared | shadcn/ui primitives — compose them, extend via variants |
30
+ | `src/core/**` | platform | hooks, lib, providers — read, never edit |
31
+ | `src/components/{checkout,auth,account,seo}` | platform | core-styled in v1; they inherit your tokens |
32
+ | `src/app/**` | platform | thin routes; edit only to wire new ui components |
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
+
54
+ ## The hook contract (your data supply)
55
+
56
+ UI components get *everything* from `@/core/hooks/*` and
57
+ `@/core/providers/store-provider` — never from `@/core/lib` directly:
58
+
59
+ - `useHomeData()` → `{ products, banners, loading }`
60
+ - `useProductListing()` → products + filters/sort/facets/pagination + handlers
61
+ - `useProductPage(product)` → variant/image selection, `priceInfo`, `inventory`,
62
+ `quantity`, `handleAddToCart`, `addingToCart`, `addedMessage`, customization
63
+ + modifier state and errors
64
+ - `useCartPage()` / `useCart()` → `{ cart, itemCount, totals, refreshCart }`
65
+
66
+ Hooks return data and handlers, never JSX. All catalog content (names, prices,
67
+ images, stock) comes from them — **never hardcode products**.
68
+
69
+ ## Verification loop (before you declare anything done)
70
+
71
+ 1. `pnpm exec tsc --noEmit` → must be 0.
72
+ 2. `pnpm dev` → drive the real flow you changed: home → listing → product →
73
+ add to cart → cart → checkout page renders.
74
+ 3. Screenshot desktop (1440) AND mobile (390), in the store's language.
75
+ 4. If the store is RTL: check nothing is left-anchored that should be
76
+ right-anchored, and directional arrows point with the reading direction.
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
+
106
+ ## Hard-won gotchas (each one cost a real debugging session)
107
+
108
+ - **RTL + cloned images**: `next/image` renders its `<img>` with `inset: 0`.
109
+ If you clone one for an animation and set `left`, the leftover `right: 0`
110
+ wins in RTL documents (over-constrained boxes resolve to the RIGHT).
111
+ Set `inset: 'auto'` before positioning.
112
+ - **Never name a custom class `overline`** — it is a Tailwind utility
113
+ (`text-decoration-line: overline`) and will draw a line above your text.
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.
117
+ - **Hebrew has no uppercase** — remove `text-transform: uppercase` and wide
118
+ `letter-spacing` from heading styles; they are Latin idioms that distort
119
+ Hebrew (tracking is acceptable only at caption sizes).
120
+ - **Logical properties only**: `ms-/me-`, `ps-/pe-`, `start-/end-`,
121
+ `text-start/end`. Never `ml-/mr-`, `left-/right-`, `text-left/right`,
122
+ `flex-row-reverse`.
123
+ - **Motion**: wrap every animation in a `prefers-reduced-motion: reduce`
124
+ guard. One well-orchestrated reveal beats scattered effects.
125
+ - **Fonts**: any face used for body or headlines must include the store's
126
+ script (e.g. Google Fonts `hebrew` subset). Latin-only display faces are
127
+ accent-only.
128
+
129
+ ## Never do
130
+
131
+ - Modify `src/core/`, `src/app/api/`, or checkout/auth/account internals.
132
+ - Remove accessibility attributes (`aria-*`, `role`, `alt`, focus styles).
133
+ - Hardcode catalog content, prices, or currency symbols.
134
+ - Swallow the add-to-cart / checkout error states — restyle them, keep them.
135
+ - Introduce new runtime dependencies without flagging it.
136
+
137
+ ## Adding things
138
+
139
+ - New homepage section → new component in `src/ui/home/`, composed in
140
+ `home-client.tsx`, data via existing hooks only.
141
+ - New UI copy → add keys to **both** `messages/he.json` and
142
+ `messages/en.json` (or all supported locales), use `useTranslations()`.
143
+ - New microinteraction → CSS-first; JS only for things CSS cannot do.
@@ -0,0 +1,52 @@
1
+ # CLAUDE.md — this is a Brainerce storefront
2
+
3
+ This store's commerce engine (cart, checkout, variants, auth, i18n) is
4
+ already wired and working. Your job here is almost always **design**.
5
+
6
+ ## The one rule
7
+
8
+ **`src/core/` is the platform's. `src/ui/` is yours.**
9
+
10
+ The shipped `src/ui/` is a working reference, not a design to preserve —
11
+ full delete-and-rebuild of ui files is encouraged and expected. (Stores
12
+ scaffolded with `--canvas` ship `src/ui/` as bare unstyled skeletons —
13
+ there is no reference look at all; the design is entirely yours to create.)
14
+ Rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
15
+ like — the store keeps working. Never modify `src/core/`, `src/app/api/`, or
16
+ the checkout/auth/account components. Data and behavior come exclusively from
17
+ `@/core/hooks/*` and `@/core/providers/store-provider` — hooks return state
18
+ and handlers, never JSX. Never hardcode catalog content.
19
+
20
+ **Read `AI-GUIDE.md` before any redesign** — it has the full file map, hook
21
+ contracts, and hard-won RTL/i18n gotchas that will save you real debugging
22
+ time.
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
+
34
+ ## Redesigning? Use the ready-made flow
35
+
36
+ Run `/design <your art-direction brief>` — it walks the whole process:
37
+ concept → implementation in `ui/` → verification.
38
+
39
+ ## Verify before declaring done
40
+
41
+ 1. `pnpm exec tsc --noEmit` → 0 errors
42
+ 2. `pnpm dev` → drive the changed flow in a real browser (home → product →
43
+ add to cart → cart)
44
+ 3. Screenshot desktop (1440px) and mobile (390px)
45
+ 4. RTL stores: check anchoring and arrow directions
46
+
47
+ ## i18n
48
+
49
+ Every user-facing string goes through `useTranslations()` with keys in **all**
50
+ files under `messages/`. Hebrew: no uppercase transforms, no wide
51
+ letter-spacing on headings, logical CSS properties only (`ms-/me-`, `ps-/pe-`,
52
+ `start-/end-`).
@@ -37,7 +37,7 @@ You write **one** `fetch` and it works for every language.
37
37
 
38
38
  ```tsx
39
39
  // src/app/[locale]/products/[slug]/page.tsx
40
- import { getServerClient } from '@/lib/server-client';
40
+ import { getServerClient } from '@/core/lib/server-client';
41
41
  import { headers } from 'next/headers';
42
42
 
43
43
  export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {
@@ -1,5 +1,5 @@
1
1
  import type { NextConfig } from 'next';
2
- import { OPTIMIZED_IMAGE_HOSTS } from './src/lib/image-hosts';
2
+ import { OPTIMIZED_IMAGE_HOSTS } from './src/core/lib/image-hosts';
3
3
 
4
4
  // Build-time invariant — fail loud if NEXT_PUBLIC_STORE_CURRENCY is missing
5
5
  // for a production build. Next.js inlines NEXT_PUBLIC_* into the client
@@ -35,7 +35,7 @@ const nextConfig: NextConfig = {
35
35
  // its image-import job is pending or failed. Rather than allowlist every
36
36
  // possible merchant host (or hard-fail on them), only cdn.brainerce.com
37
37
  // goes through the server-side optimizer; components render product/blog
38
- // images via `CdnImage` (src/components/shared/cdn-image.tsx), which
38
+ // images via `CdnImage` (src/ui/shared/cdn-image.tsx), which
39
39
  // detects any other host and renders it `unoptimized` — an unresized
40
40
  // direct-from-origin fetch, same as this template's prior behavior —
41
41
  // instead of next/image throwing on an unconfigured hostname. No
@@ -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,15 +1,15 @@
1
1
  'use client';
2
2
 
3
3
  import { useEffect, useState } from 'react';
4
- import { useRouter } from '@/lib/navigation';
4
+ import { useRouter } from '@/core/lib/navigation';
5
5
  import type { CustomerProfile, Order } from 'brainerce';
6
- import { getClient } from '@/lib/brainerce';
7
- import { useAuth } from '@/providers/store-provider';
8
- import { LoadingSpinner } from '@/components/shared/loading-spinner';
6
+ import { getClient } from '@/core/lib/brainerce';
7
+ import { useAuth } from '@/core/providers/store-provider';
8
+ import { LoadingSpinner } from '@/ui/shared/loading-spinner';
9
9
  import { ProfileSection } from '@/components/account/profile-section';
10
10
  import { AddressBook } from '@/components/account/address-book';
11
11
  import { OrderHistory } from '@/components/account/order-history';
12
- import { useTranslations } from '@/lib/translations';
12
+ import { useTranslations } from '@/core/lib/translations';
13
13
 
14
14
  export default function AccountPage() {
15
15
  const router = useRouter();
@@ -1,5 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { checkCsrf } from '@/lib/csrf';
2
+ import { checkCsrf } from '@/core/lib/csrf';
3
3
 
4
4
  const TOKEN_COOKIE = 'brainerce_customer_token';
5
5
  const LOGGED_IN_COOKIE = 'brainerce_logged_in';
@@ -1,7 +1,7 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  import { cookies } from 'next/headers';
3
- import { validatePassword } from '@/lib/validation';
4
- import { checkCsrf } from '@/lib/csrf';
3
+ import { validatePassword } from '@/core/lib/validation';
4
+ import { checkCsrf } from '@/core/lib/csrf';
5
5
 
6
6
  const BACKEND_URL = (process.env.BRAINERCE_API_URL || 'https://api.brainerce.com').replace(
7
7
  /\/$/,
@@ -5,7 +5,7 @@
5
5
  // like customers/login and customers/register are the most important to cover.
6
6
  import { NextRequest, NextResponse } from 'next/server';
7
7
  import { cookies } from 'next/headers';
8
- import { checkCsrf } from '@/lib/csrf';
8
+ import { checkCsrf } from '@/core/lib/csrf';
9
9
 
10
10
  const BACKEND_URL = (process.env.BRAINERCE_API_URL || 'https://api.brainerce.com').replace(
11
11
  /\/$/,
@@ -2,10 +2,10 @@
2
2
 
3
3
  import { Suspense, useEffect, useState, useRef } from 'react';
4
4
  import { useSearchParams } from 'next/navigation';
5
- import { useRouter } from '@/lib/navigation';
6
- import { useAuth } from '@/providers/store-provider';
7
- import { LoadingSpinner } from '@/components/shared/loading-spinner';
8
- import { useTranslations } from '@/lib/translations';
5
+ import { useRouter } from '@/core/lib/navigation';
6
+ import { useAuth } from '@/core/providers/store-provider';
7
+ import { LoadingSpinner } from '@/ui/shared/loading-spinner';
8
+ import { useTranslations } from '@/core/lib/translations';
9
9
 
10
10
  function OAuthCallbackContent() {
11
11
  const router = useRouter();
@@ -12,11 +12,11 @@ import * as React from 'react';
12
12
  import type { Metadata } from 'next';
13
13
  import { notFound } from 'next/navigation';
14
14
  import Link from 'next/link';
15
- import { CdnImage as Image } from '@/components/shared/cdn-image';
15
+ import { CdnImage as Image } from '@/ui/shared/cdn-image';
16
16
 
17
- import { getServerClient } from '@/lib/brainerce';
18
- import { sanitizeHtml } from '@/lib/sanitize';
19
- import { decodeSlug } from '@/lib/utils';
17
+ import { getServerClient } from '@/core/lib/brainerce';
18
+ import { sanitizeHtml } from '@/core/lib/sanitize';
19
+ import { decodeSlug } from '@/core/lib/utils';
20
20
 
21
21
  <% if (i18nEnabled) { %>
22
22
  type PageProps = {
@@ -10,9 +10,9 @@
10
10
  import * as React from 'react';
11
11
  import type { Metadata } from 'next';
12
12
  import Link from 'next/link';
13
- import { CdnImage as Image } from '@/components/shared/cdn-image';
13
+ import { CdnImage as Image } from '@/ui/shared/cdn-image';
14
14
 
15
- import { getServerClient } from '@/lib/brainerce';
15
+ import { getServerClient } from '@/core/lib/brainerce';
16
16
 
17
17
  <% if (i18nEnabled) { %>
18
18
  type PageProps = {