@pradip1995/theme-valero 1.0.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 (44) hide show
  1. package/README.md +16 -0
  2. package/package.json +59 -0
  3. package/src/blocks/home/Features/index.tsx +61 -0
  4. package/src/blocks/home/Hero/index.tsx +102 -0
  5. package/src/blocks/home/LovedByMoms/index.tsx +407 -0
  6. package/src/blocks/home/NewArrivals/index.tsx +48 -0
  7. package/src/blocks/home/ShopByAge/index.tsx +128 -0
  8. package/src/blocks/home/ShopByCategory/index.tsx +409 -0
  9. package/src/blocks/home/Testimonials/index.tsx +697 -0
  10. package/src/blocks/home/WhyChooseUs/index.tsx +62 -0
  11. package/src/layouts/MainLayoutShell.tsx +14 -0
  12. package/src/primitives/Button.tsx +30 -0
  13. package/src/primitives/Card.tsx +32 -0
  14. package/src/primitives/index.ts +2 -0
  15. package/src/slots/account/ForgotPassword/index.tsx +1 -0
  16. package/src/slots/account/Login/index.tsx +1 -0
  17. package/src/slots/account/LoginTemplate/index.tsx +44 -0
  18. package/src/slots/account/Register/index.tsx +1 -0
  19. package/src/slots/cart/CartItem/index.tsx +11 -0
  20. package/src/slots/cart/CartSummary/index.tsx +13 -0
  21. package/src/slots/checkout/CheckoutForm/index.tsx +1 -0
  22. package/src/slots/checkout/CheckoutSummary/index.tsx +1 -0
  23. package/src/slots/layout/Footer/index.tsx +104 -0
  24. package/src/slots/layout/Nav/index.tsx +97 -0
  25. package/src/slots/layout/PromoBar/index.tsx +19 -0
  26. package/src/slots/layout/PromoBar/promo-bar-content.tsx +174 -0
  27. package/src/slots/order/OrderDetails/index.tsx +12 -0
  28. package/src/slots/product/ProductActions/ProductCTASection.tsx +191 -0
  29. package/src/slots/product/ProductActions/ProductDetailsSection.tsx +137 -0
  30. package/src/slots/product/ProductActions/ProductFeaturePanel.tsx +245 -0
  31. package/src/slots/product/ProductActions/ProductHighlightsSection.tsx +99 -0
  32. package/src/slots/product/ProductActions/ProductOptionsSection.tsx +234 -0
  33. package/src/slots/product/ProductActions/ProductPriceSection.tsx +53 -0
  34. package/src/slots/product/ProductActions/ProductTrustSection.tsx +84 -0
  35. package/src/slots/product/ProductActions/index.tsx +161 -0
  36. package/src/slots/product/ProductCard/index.tsx +132 -0
  37. package/src/slots/product/ProductInfo/index.tsx +40 -0
  38. package/src/templates/StorePage/index.tsx +154 -0
  39. package/src/tokens/colors.js +16 -0
  40. package/src/tokens/colors.ts +21 -0
  41. package/src/tokens/fonts.ts +13 -0
  42. package/src/tokens/index.ts +3 -0
  43. package/src/tokens/spacing.ts +9 -0
  44. package/src/tokens/theme.css +91 -0
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # @pradip1995/theme-valero
2
+
3
+ Impulse-inspired storefront theme. Use as an npm package or copy to customize.
4
+
5
+ ## Use as package (override CSS only)
6
+
7
+ ```ts
8
+ // next.config.js — @theme → node_modules/@pradip1995/theme-valero/src
9
+ import "@pradip1995/theme-valero/tokens/theme.css"
10
+ ```
11
+
12
+ ## Fork for full customization
13
+
14
+ ```bash
15
+ ./scripts/create-theme.sh my-brand --from valero
16
+ ```
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@pradip1995/theme-valero",
3
+ "version": "1.0.1",
4
+ "description": "Valero Medusa storefront theme — Impulse-inspired design tokens and components",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public",
8
+ "registry": "https://registry.npmjs.org/"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/SmartByteLabs/medusa-storefront-kit.git",
13
+ "directory": "packages/theme-valero"
14
+ },
15
+ "sideEffects": [
16
+ "**/*.css"
17
+ ],
18
+ "files": [
19
+ "src"
20
+ ],
21
+ "exports": {
22
+ "./tokens/theme.css": "./src/tokens/theme.css",
23
+ "./tokens": "./src/tokens/index.ts",
24
+ "./tokens/*": "./src/tokens/*",
25
+ "./layouts/*": "./src/layouts/*",
26
+ "./primitives": "./src/primitives/index.ts",
27
+ "./primitives/*": "./src/primitives/*",
28
+ "./blocks/*": "./src/blocks/*/index.tsx",
29
+ "./slots/*": "./src/slots/*/index.tsx",
30
+ "./*": "./src/*"
31
+ },
32
+ "peerDependencies": {
33
+ "@pradip1995/commerce-auth": "^1.0.1",
34
+ "@pradip1995/commerce-core": "^1.0.1",
35
+ "@medusajs/types": ">=2",
36
+ "@medusajs/ui": ">=4",
37
+ "color": ">=5",
38
+ "next": ">=15",
39
+ "react": ">=19",
40
+ "react-dom": ">=19"
41
+ },
42
+ "devDependencies": {
43
+ "@medusajs/types": "latest",
44
+ "@medusajs/ui": "latest",
45
+ "@types/color": "^4.2.0",
46
+ "@types/react": "^19",
47
+ "color": "^5.0.3",
48
+ "next": "15.3.8",
49
+ "react": "19.0.3",
50
+ "react-dom": "19.0.3",
51
+ "typescript": "^5.7.2",
52
+ "@pradip1995/commerce-auth": "1.0.1",
53
+ "@pradip1995/commerce-core": "1.0.1"
54
+ },
55
+ "scripts": {
56
+ "typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
57
+ "lint": "tsc --noEmit -p tsconfig.typecheck.json"
58
+ }
59
+ }
@@ -0,0 +1,61 @@
1
+ import Image from "next/image"
2
+
3
+ const features = [
4
+ {
5
+ name: "100% Secure",
6
+ icon: "/secure.svg",
7
+ },
8
+ {
9
+ name: "Easy Exchanges",
10
+ icon: "/exchnage.svg",
11
+ },
12
+ {
13
+ name: "Fast Delivery",
14
+ icon: "/fast.svg",
15
+ },
16
+ {
17
+ name: "Cash On Delivery",
18
+ icon: "/cash.svg",
19
+ },
20
+ ]
21
+
22
+ const Features = () => {
23
+ return (
24
+ <div className="w-full py-4 min-[350px]:py-5 sm:py-6 md:py-8 lg:py-10 px-3 min-[350px]:px-4 sm:px-6 md:px-8 lg:px-12 bg-page-bg">
25
+ <div className="max-w-[1360px] mx-auto w-full">
26
+ {/* Responsive Grid: 4 columns across all screens, but adjusted sizing/layout */}
27
+ <div className="grid grid-cols-4 gap-2 sm:gap-4 md:gap-6 lg:gap-8 items-start justify-items-center">
28
+ {features.map((feature, index) => (
29
+ <div
30
+ key={feature.name}
31
+ className={`
32
+ flex flex-col sm:flex-row items-center justify-start
33
+ w-full relative px-1 sm:px-2
34
+ ${index < features.length - 1 ? 'sm:border-r border-gray-200' : ''}
35
+ `}
36
+ >
37
+ <div className="relative w-8 h-8 xs:w-10 xs:h-10 sm:w-10 sm:h-10 md:w-12 md:h-12 lg:w-14 lg:h-14 xl:w-20 xl:h-20 mb-1.5 sm:mb-0 sm:mr-2 md:mr-3 lg:mr-4 flex-shrink-0">
38
+ <Image
39
+ src={feature.icon}
40
+ alt={feature.name}
41
+ width={80}
42
+ height={80}
43
+ className="w-full h-full object-contain"
44
+ unoptimized
45
+ />
46
+ </div>
47
+ <div className="text-center sm:text-left min-w-0">
48
+ <h3 className="text-[8px] xs:text-[10px] sm:text-[11px] md:text-sm lg:text-base xl:text-lg font-semibold text-gray-800 leading-tight">
49
+ {feature.name}
50
+ </h3>
51
+ </div>
52
+ </div>
53
+ ))}
54
+ </div>
55
+ </div>
56
+ </div>
57
+ )
58
+ }
59
+
60
+ export default Features
61
+
@@ -0,0 +1,102 @@
1
+ import Image from "next/image"
2
+ import LocalizedClientLink from "@modules/common/components/localized-client-link"
3
+ import type { HeroBlockData } from "@core/types/home"
4
+
5
+ const Hero = ({ homeBanner, appBanner }: HeroBlockData) => {
6
+ const desktopImage = homeBanner.image || "/newbanner.png"
7
+ const mobileImage = appBanner.image || desktopImage
8
+
9
+ return (
10
+ <section className="w-full">
11
+ {/* Desktop — Impulse full-bleed hero with overlay */}
12
+ <div className="hidden min-[551px]:block relative w-full min-h-[420px] md:min-h-[520px] lg:min-h-[600px]">
13
+ <Image
14
+ src={desktopImage}
15
+ alt={homeBanner.subtitle || homeBanner.title || "Hero banner"}
16
+ fill
17
+ priority
18
+ sizes="100vw"
19
+ className="object-cover"
20
+ />
21
+ <div
22
+ className="absolute inset-0"
23
+ style={{ background: "var(--gradient-hero)" }}
24
+ />
25
+ <div className="absolute inset-0 flex items-end">
26
+ <div
27
+ className="w-full mx-auto px-8 md:px-12 lg:px-16 pb-12 md:pb-16 lg:pb-20"
28
+ style={{ maxWidth: "var(--container-max)" }}
29
+ >
30
+ <div className="max-w-xl text-[var(--color-text-inverse)]">
31
+ {homeBanner.title && (
32
+ <p className="text-xs md:text-sm font-semibold uppercase tracking-[var(--letter-spacing-nav)] mb-3 opacity-90">
33
+ {homeBanner.title}
34
+ </p>
35
+ )}
36
+ {homeBanner.subtitle && (
37
+ <h1 className="font-display text-3xl md:text-5xl lg:text-6xl font-normal leading-heading mb-4">
38
+ {homeBanner.subtitle}
39
+ </h1>
40
+ )}
41
+ {homeBanner.description && (
42
+ <p className="text-sm md:text-base text-white/85 mb-8 max-w-md leading-relaxed">
43
+ {homeBanner.description}
44
+ </p>
45
+ )}
46
+ {homeBanner.buttonName && (
47
+ <LocalizedClientLink href={homeBanner.buttonLink || "/store"}>
48
+ <span
49
+ className="inline-block border-2 border-white text-white px-8 py-3 text-xs font-semibold uppercase tracking-[var(--letter-spacing-nav)] hover:bg-white hover:text-brand-accent transition-colors duration-300"
50
+ data-ga-event="hero_banner_click"
51
+ data-ga-label={homeBanner.buttonName}
52
+ >
53
+ {homeBanner.buttonName}
54
+ </span>
55
+ </LocalizedClientLink>
56
+ )}
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+
62
+ {/* Mobile */}
63
+ <div className="block min-[551px]:hidden relative w-full min-h-[480px]">
64
+ <Image
65
+ src={mobileImage}
66
+ alt={appBanner.subtitle || appBanner.title || "Hero banner"}
67
+ fill
68
+ priority
69
+ sizes="100vw"
70
+ className="object-cover"
71
+ />
72
+ <div
73
+ className="absolute inset-0"
74
+ style={{ background: "var(--gradient-hero)" }}
75
+ />
76
+ <div className="absolute inset-0 flex items-end px-6 pb-10">
77
+ <div className="text-[var(--color-text-inverse)]">
78
+ {appBanner.title && (
79
+ <p className="text-xs font-semibold uppercase tracking-[var(--letter-spacing-nav)] mb-2 opacity-90">
80
+ {appBanner.title}
81
+ </p>
82
+ )}
83
+ {appBanner.subtitle && (
84
+ <h1 className="font-display text-2xl font-normal leading-heading mb-3">
85
+ {appBanner.subtitle}
86
+ </h1>
87
+ )}
88
+ {appBanner.buttonName && (
89
+ <LocalizedClientLink href={appBanner.buttonLink || "/store"}>
90
+ <span className="inline-block border-2 border-white text-white px-6 py-2.5 text-[11px] font-semibold uppercase tracking-[var(--letter-spacing-nav)]">
91
+ {appBanner.buttonName}
92
+ </span>
93
+ </LocalizedClientLink>
94
+ )}
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </section>
99
+ )
100
+ }
101
+
102
+ export default Hero
@@ -0,0 +1,407 @@
1
+ "use client"
2
+
3
+ import Image from "next/image"
4
+ import LocalizedClientLink from "@modules/common/components/localized-client-link"
5
+ import { HttpTypes } from "@medusajs/types"
6
+ import ProductCard from "@theme/slots/product/ProductCard"
7
+
8
+ type LovedByMomsProps = {
9
+ products: HttpTypes.StoreProduct[]
10
+ region: HttpTypes.StoreRegion
11
+ ratings?: any[]
12
+ }
13
+
14
+ const LovedByMoms = ({ products, region, ratings }: LovedByMomsProps) => {
15
+ const safeProducts = products || []
16
+
17
+ if (safeProducts.length === 0) {
18
+ return null
19
+ }
20
+
21
+ return (
22
+ <>
23
+ <style dangerouslySetInnerHTML={{
24
+ __html: `
25
+ @media (min-width: 340px) and (max-width: 419px) {
26
+ .loved-by-moms-banner {
27
+ padding: 1rem !important;
28
+ min-height: auto !important;
29
+ border-radius: 1rem !important;
30
+ }
31
+ .loved-by-moms-left-section {
32
+ width: 100% !important;
33
+ margin-bottom: 1rem !important;
34
+ }
35
+ .loved-by-moms-title {
36
+ font-size: 1.25rem !important;
37
+ margin-bottom: 0.5rem !important;
38
+ }
39
+ .loved-by-moms-text {
40
+ font-size: 0.75rem !important;
41
+ margin-bottom: 0.375rem !important;
42
+ }
43
+ .loved-by-moms-button {
44
+ padding: 0.5rem 1rem !important;
45
+ font-size: 0.75rem !important;
46
+ }
47
+ .loved-by-moms-cards-container {
48
+ width: 100% !important;
49
+ max-width: 100% !important;
50
+ overflow-x: auto !important;
51
+ overflow-y: hidden !important;
52
+ -webkit-overflow-scrolling: touch !important;
53
+ scrollbar-width: thin !important;
54
+ scrollbar-color: rgba(139, 90, 177, 0.3) transparent !important;
55
+ padding-left: 0 !important;
56
+ padding-right: 0 !important;
57
+ }
58
+ .loved-by-moms-cards-container::-webkit-scrollbar {
59
+ height: 4px !important;
60
+ }
61
+ .loved-by-moms-cards-container::-webkit-scrollbar-track {
62
+ background: transparent !important;
63
+ }
64
+ .loved-by-moms-cards-container::-webkit-scrollbar-thumb {
65
+ background-color: rgba(139, 90, 177, 0.3) !important;
66
+ border-radius: 2px !important;
67
+ }
68
+ .loved-by-moms-cards-flex {
69
+ gap: 0.75rem !important;
70
+ padding-left: 0.5rem !important;
71
+ padding-right: 0.5rem !important;
72
+ }
73
+ .loved-by-moms-card {
74
+ width: 140px !important;
75
+ min-width: 140px !important;
76
+ max-width: 140px !important;
77
+ height: auto !important;
78
+ min-height: 200px !important;
79
+ }
80
+ .loved-by-moms-image {
81
+ width: 120px !important;
82
+ height: 120px !important;
83
+ }
84
+ .loved-by-moms-star {
85
+ width: 0.625rem !important;
86
+ height: 0.625rem !important;
87
+ }
88
+ .loved-by-moms-card-title {
89
+ font-size: 0.75rem !important;
90
+ margin-bottom: 0.375rem !important;
91
+ }
92
+ .loved-by-moms-price {
93
+ font-size: 0.8125rem !important;
94
+ }
95
+ }
96
+ @media (min-width: 420px) and (max-width: 549px) {
97
+ .loved-by-moms-banner {
98
+ padding: 1.25rem !important;
99
+ min-height: auto !important;
100
+ border-radius: 1.125rem !important;
101
+ }
102
+ .loved-by-moms-left-section {
103
+ width: 100% !important;
104
+ margin-bottom: 1.25rem !important;
105
+ }
106
+ .loved-by-moms-title {
107
+ font-size: 1.375rem !important;
108
+ margin-bottom: 0.625rem !important;
109
+ }
110
+ .loved-by-moms-text {
111
+ font-size: 0.8125rem !important;
112
+ margin-bottom: 0.5rem !important;
113
+ }
114
+ .loved-by-moms-button {
115
+ padding: 0.5625rem 1.125rem !important;
116
+ font-size: 0.8125rem !important;
117
+ }
118
+ .loved-by-moms-cards-container {
119
+ width: 100% !important;
120
+ max-width: 100% !important;
121
+ overflow-x: auto !important;
122
+ overflow-y: hidden !important;
123
+ -webkit-overflow-scrolling: touch !important;
124
+ scrollbar-width: thin !important;
125
+ scrollbar-color: rgba(139, 90, 177, 0.3) transparent !important;
126
+ padding-left: 0 !important;
127
+ padding-right: 0 !important;
128
+ }
129
+ .loved-by-moms-cards-container::-webkit-scrollbar {
130
+ height: 4px !important;
131
+ }
132
+ .loved-by-moms-cards-container::-webkit-scrollbar-track {
133
+ background: transparent !important;
134
+ }
135
+ .loved-by-moms-cards-container::-webkit-scrollbar-thumb {
136
+ background-color: rgba(139, 90, 177, 0.3) !important;
137
+ border-radius: 2px !important;
138
+ }
139
+ .loved-by-moms-cards-flex {
140
+ gap: 0.875rem !important;
141
+ padding-left: 0.75rem !important;
142
+ padding-right: 0.75rem !important;
143
+ }
144
+ .loved-by-moms-card {
145
+ width: 150px !important;
146
+ min-width: 150px !important;
147
+ max-width: 150px !important;
148
+ height: auto !important;
149
+ min-height: 210px !important;
150
+ }
151
+ .loved-by-moms-image {
152
+ width: 130px !important;
153
+ height: 130px !important;
154
+ }
155
+ .loved-by-moms-star {
156
+ width: 0.6875rem !important;
157
+ height: 0.6875rem !important;
158
+ }
159
+ .loved-by-moms-card-title {
160
+ font-size: 0.78125rem !important;
161
+ margin-bottom: 0.4375rem !important;
162
+ }
163
+ .loved-by-moms-price {
164
+ font-size: 0.84375rem !important;
165
+ }
166
+ }
167
+ @media (min-width: 550px) and (max-width: 767px) {
168
+ .loved-by-moms-banner-inner {
169
+ flex-direction: row !important;
170
+ align-items: center !important;
171
+ }
172
+ .loved-by-moms-banner {
173
+ padding: 1.25rem !important;
174
+ min-height: auto !important;
175
+ max-width: 100% !important;
176
+ }
177
+ .loved-by-moms-left-section {
178
+ width: 280px !important;
179
+ flex-shrink: 0 !important;
180
+ text-align: left !important;
181
+ margin-bottom: 0 !important;
182
+ }
183
+ .loved-by-moms-title {
184
+ font-size: 1.375rem !important;
185
+ text-align: left !important;
186
+ margin-bottom: 0.625rem !important;
187
+ }
188
+ .loved-by-moms-text {
189
+ font-size: 0.8125rem !important;
190
+ text-align: left !important;
191
+ margin-bottom: 0.375rem !important;
192
+ }
193
+ .loved-by-moms-button {
194
+ padding: 0.5rem 1.25rem !important;
195
+ font-size: 0.8125rem !important;
196
+ }
197
+ .loved-by-moms-cards-wrapper {
198
+ flex: 1 !important;
199
+ min-width: 0 !important;
200
+ }
201
+ .loved-by-moms-cards-container {
202
+ width: 100% !important;
203
+ max-width: 100% !important;
204
+ overflow-x: auto !important;
205
+ overflow-y: hidden !important;
206
+ -webkit-overflow-scrolling: touch !important;
207
+ }
208
+ .loved-by-moms-cards-flex {
209
+ gap: 0.625rem !important;
210
+ justify-content: flex-start !important;
211
+ }
212
+ .loved-by-moms-card {
213
+ width: 165px !important;
214
+ min-width: 165px !important;
215
+ max-width: 165px !important;
216
+ height: auto !important;
217
+ min-height: 230px !important;
218
+ }
219
+ .loved-by-moms-image {
220
+ width: 150px !important;
221
+ height: 150px !important;
222
+ }
223
+ .loved-by-moms-star {
224
+ width: 0.8125rem !important;
225
+ height: 0.8125rem !important;
226
+ }
227
+ .loved-by-moms-card-title {
228
+ font-size: 0.8125rem !important;
229
+ text-align: left !important;
230
+ margin-bottom: 0.375rem !important;
231
+ }
232
+ .loved-by-moms-price {
233
+ font-size: 0.9375rem !important;
234
+ text-align: left !important;
235
+ }
236
+ }
237
+ @media (min-width: 768px) and (max-width: 1440px) {
238
+ .loved-by-moms-banner {
239
+ padding: 2rem !important;
240
+ min-height: auto !important;
241
+ max-width: 100% !important;
242
+ }
243
+ .loved-by-moms-left-section {
244
+ width: 350px !important;
245
+ flex-shrink: 0 !important;
246
+ text-align: left !important;
247
+ }
248
+ .loved-by-moms-title {
249
+ font-size: 2rem !important;
250
+ text-align: left !important;
251
+ margin-bottom: 1rem !important;
252
+ }
253
+ .loved-by-moms-text {
254
+ font-size: 1rem !important;
255
+ text-align: left !important;
256
+ margin-bottom: 0.5rem !important;
257
+ }
258
+ .loved-by-moms-button {
259
+ padding: 0.75rem 2rem !important;
260
+ font-size: 1rem !important;
261
+ }
262
+ .loved-by-moms-cards-wrapper {
263
+ flex: 1 !important;
264
+ min-width: 0 !important;
265
+ }
266
+ .loved-by-moms-cards-container {
267
+ width: 100% !important;
268
+ max-width: 723px !important;
269
+ overflow-x: auto !important;
270
+ overflow-y: hidden !important;
271
+ -webkit-overflow-scrolling: touch !important;
272
+ scrollbar-width: thin !important;
273
+ scrollbar-color: rgba(139, 90, 177, 0.3) transparent !important;
274
+ }
275
+ .loved-by-moms-cards-container::-webkit-scrollbar {
276
+ height: 4px !important;
277
+ }
278
+ .loved-by-moms-cards-container::-webkit-scrollbar-track {
279
+ background: transparent !important;
280
+ }
281
+ .loved-by-moms-cards-container::-webkit-scrollbar-thumb {
282
+ background-color: rgba(139, 90, 177, 0.3) !important;
283
+ border-radius: 2px !important;
284
+ }
285
+ .loved-by-moms-card {
286
+ width: 220px !important;
287
+ min-width: 220px !important;
288
+ height: 282px !important;
289
+ }
290
+ .loved-by-moms-image {
291
+ width: 200px !important;
292
+ height: 200px !important;
293
+ }
294
+ .loved-by-moms-star {
295
+ width: 1rem !important;
296
+ height: 1rem !important;
297
+ }
298
+ .loved-by-moms-card-title {
299
+ font-size: 1rem !important;
300
+ text-align: left !important;
301
+ margin-bottom: 0.5rem !important;
302
+ }
303
+ .loved-by-moms-price {
304
+ font-size: 1.125rem !important;
305
+ text-align: left !important;
306
+ }
307
+ }
308
+ @media (min-width: 1441px) {
309
+ .loved-by-moms-banner {
310
+ max-width: 1360px !important;
311
+ }
312
+ .loved-by-moms-left-section {
313
+ width: 400px !important;
314
+ flex-shrink: 0 !important;
315
+ }
316
+ .loved-by-moms-cards-wrapper {
317
+ flex: 1 !important;
318
+ min-width: 0 !important;
319
+ }
320
+ .loved-by-moms-cards-container {
321
+ width: 100% !important;
322
+ max-width: 723px !important;
323
+ overflow-x: auto !important;
324
+ overflow-y: hidden !important;
325
+ -webkit-overflow-scrolling: touch !important;
326
+ }
327
+ .loved-by-moms-card {
328
+ width: 220px !important;
329
+ min-width: 220px !important;
330
+ height: 282px !important;
331
+ }
332
+ .loved-by-moms-image {
333
+ width: 200px !important;
334
+ height: 200px !important;
335
+ }
336
+ }
337
+ `
338
+ }} />
339
+ <div className="w-full py-8 sm:py-12 md:py-14 lg:py-16 bg-page-bg">
340
+ <div className="w-full px-4 sm:px-6 md:px-8 lg:px-12 xl:px-16">
341
+ <div className="w-full flex justify-center">
342
+ <div className="bg-gradient-to-r from-purple-100 to-pink-100 rounded-2xl sm:rounded-3xl p-6 sm:p-8 md:p-10 lg:p-12 w-full loved-by-moms-banner" style={{ maxWidth: '1360px', minHeight: 'auto' }}>
343
+ <div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 sm:gap-6 md:gap-8 lg:gap-10 h-full loved-by-moms-banner-inner">
344
+ {/* Left Section - Text Content */}
345
+ <div className="w-full md:w-[400px] flex-shrink-0 loved-by-moms-left-section text-center md:text-left">
346
+ <h2 className="text-2xl sm:text-3xl md:text-3xl lg:text-4xl font-bold mb-3 sm:mb-4 loved-by-moms-title text-heading">
347
+ Loved by Moms
348
+ </h2>
349
+ <p className="text-sm sm:text-base md:text-lg text-gray-700 mb-2 loved-by-moms-text">
350
+ Top-rated styles loved by parents and kids alike.
351
+ </p>
352
+ <p className="text-sm sm:text-base md:text-lg text-gray-700 mb-4 sm:mb-6 loved-by-moms-text">
353
+ 5-star comfort guaranteed!
354
+ </p>
355
+ <LocalizedClientLink
356
+ href="/store?sortBy=bestsellers"
357
+ data-ga-event="shop_bestsellers_click"
358
+ data-ga-label="Shop Bestsellers Banner"
359
+ className="inline-flex items-center gap-2 px-6 sm:px-8 py-2.5 sm:py-3 rounded-full text-white text-sm sm:text-base font-medium transition-colors duration-200 hover:opacity-90 loved-by-moms-button bg-brand-accent"
360
+ >
361
+ Shop Bestsellers
362
+ <svg
363
+ className="w-4 h-4 sm:w-5 sm:h-5"
364
+ fill="none"
365
+ stroke="currentColor"
366
+ viewBox="0 0 24 24"
367
+ >
368
+ <path
369
+ strokeLinecap="round"
370
+ strokeLinejoin="round"
371
+ strokeWidth={2}
372
+ d="M9 5l7 7-7 7"
373
+ />
374
+ </svg>
375
+ </LocalizedClientLink>
376
+ </div>
377
+
378
+ {/* Right Section - Product Cards */}
379
+ <div className="w-full md:flex-1 min-w-0 loved-by-moms-cards-wrapper">
380
+ <div className="loved-by-moms-cards-container overflow-x-auto no-scrollbar">
381
+ <div className="flex gap-4 pb-2 sm:pb-4 justify-start loved-by-moms-cards-flex">
382
+ {safeProducts.map((product) => (
383
+ <div
384
+ key={product.id}
385
+ className="flex-shrink-0 loved-by-moms-card w-[160px] sm:w-[200px] md:w-[240px]"
386
+ >
387
+ <ProductCard
388
+ product={product}
389
+ region={region}
390
+ rating={ratings?.find((r) => r.product_id === product.id)}
391
+ />
392
+ </div>
393
+ ))}
394
+ </div>
395
+ </div>
396
+ </div>
397
+ </div>
398
+ </div>
399
+ </div>
400
+ </div>
401
+ </div>
402
+ </>
403
+ )
404
+ }
405
+
406
+ export default LovedByMoms
407
+
@@ -0,0 +1,48 @@
1
+ "use client"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import ProductCard from "@theme/slots/product/ProductCard"
5
+
6
+ type NewArrivalsProps = {
7
+ products: HttpTypes.StoreProduct[]
8
+ region: HttpTypes.StoreRegion
9
+ ratings?: any[]
10
+ }
11
+
12
+ const NewArrivals = ({ products, region, ratings }: NewArrivalsProps) => {
13
+ const safeProducts = (products || []).slice(0, 8) // Show only first 8 products
14
+
15
+ return (
16
+ <div className="w-full py-8 sm:py-12 md:py-14 lg:py-16 bg-page-bg">
17
+ <div className="w-full px-4 sm:px-6 md:px-8 lg:px-12 xl:px-16">
18
+ <div className="mx-auto" style={{ maxWidth: '1360px' }}>
19
+ <div className="flex items-center justify-between mb-8 md:mb-10">
20
+ <h2 className="font-display text-2xl md:text-3xl text-heading">
21
+ New Arrivals
22
+ </h2>
23
+ </div>
24
+
25
+ <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-6 lg:gap-8">
26
+ {safeProducts.length > 0 ? (
27
+ safeProducts.map((product) => (
28
+ <ProductCard
29
+ key={product.id}
30
+ product={product}
31
+ region={region}
32
+ rating={ratings?.find((r) => r.product_id === product.id)}
33
+ />
34
+ ))
35
+ ) : (
36
+ <div className="col-span-2 md:col-span-4 text-center py-12">
37
+ <p className="text-gray-500">No new arrivals at the moment. Check back soon!</p>
38
+ </div>
39
+ )}
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ )
45
+ }
46
+
47
+ export default NewArrivals
48
+