@pradip1995/segment-powerhouse-shop 0.1.1 → 0.1.2
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.
- package/package.json +1 -1
- package/src/add-to-cart.ts +24 -0
- package/src/product-card.tsx +10 -10
- package/src/shop.css +241 -63
- package/src/shop.tsx +256 -138
package/package.json
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
|
|
3
|
+
import { addToCart as addToCartCore } from "@pradip1995/commerce-core/data/cart"
|
|
4
|
+
import { removeAuthToken, removeCartId } from "@pradip1995/commerce-core/data/cookies"
|
|
5
|
+
|
|
6
|
+
function isStaleCustomerError(err: unknown) {
|
|
7
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
8
|
+
return /customer with id/i.test(message) && /not found/i.test(message)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function addToCart(input: {
|
|
12
|
+
variantId: string
|
|
13
|
+
quantity: number
|
|
14
|
+
countryCode: string
|
|
15
|
+
}) {
|
|
16
|
+
try {
|
|
17
|
+
await addToCartCore(input)
|
|
18
|
+
} catch (err) {
|
|
19
|
+
if (!isStaleCustomerError(err)) throw err
|
|
20
|
+
await removeAuthToken()
|
|
21
|
+
await removeCartId()
|
|
22
|
+
await addToCartCore(input)
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/product-card.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useState, type MouseEvent } from "react"
|
|
4
4
|
import { useRouter } from "next/navigation"
|
|
5
|
-
import { addToCart } from "
|
|
5
|
+
import { addToCart } from "./add-to-cart"
|
|
6
6
|
import LocalizedLink from "@pradip1995/segment-primitives/localized-link"
|
|
7
7
|
import { formatPrice } from "@pradip1995/segment-primitives/format-price"
|
|
8
8
|
import { isNextRedirect } from "@pradip1995/segment-primitives/is-next-redirect"
|
|
@@ -82,6 +82,15 @@ export default function ShopProductCard({
|
|
|
82
82
|
</LocalizedLink>
|
|
83
83
|
|
|
84
84
|
<div className="powerhouse-shop__info">
|
|
85
|
+
{price != null ? (
|
|
86
|
+
<div className="powerhouse-shop__price">
|
|
87
|
+
{onSale && originalPrice != null ? (
|
|
88
|
+
<span className="powerhouse-shop__compare">{formatPrice(originalPrice, currency)}</span>
|
|
89
|
+
) : null}
|
|
90
|
+
<span className="powerhouse-shop__current">{formatPrice(price, currency)}</span>
|
|
91
|
+
</div>
|
|
92
|
+
) : null}
|
|
93
|
+
|
|
85
94
|
<h2 className="powerhouse-shop__name">
|
|
86
95
|
<LocalizedLink href={href} countryCode={countryCode}>
|
|
87
96
|
{product.title}
|
|
@@ -98,15 +107,6 @@ export default function ShopProductCard({
|
|
|
98
107
|
|
|
99
108
|
{copy ? <p className="powerhouse-shop__excerpt">{copy}</p> : null}
|
|
100
109
|
|
|
101
|
-
{price != null ? (
|
|
102
|
-
<div className="powerhouse-shop__price">
|
|
103
|
-
{onSale && originalPrice != null ? (
|
|
104
|
-
<span className="powerhouse-shop__compare">{formatPrice(originalPrice, currency)}</span>
|
|
105
|
-
) : null}
|
|
106
|
-
<span className="powerhouse-shop__current">{formatPrice(price, currency)}</span>
|
|
107
|
-
</div>
|
|
108
|
-
) : null}
|
|
109
|
-
|
|
110
110
|
<div className="powerhouse-shop__actions">
|
|
111
111
|
<LocalizedLink href={href} countryCode={countryCode} className="powerhouse-shop__quickshop">
|
|
112
112
|
Quick shop
|
package/src/shop.css
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
html.powerhouse-filters-open,
|
|
2
|
+
html.powerhouse-filters-open body {
|
|
3
|
+
overflow: hidden;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.powerhouse-shop .sr-only {
|
|
7
|
+
position: absolute;
|
|
8
|
+
width: 1px;
|
|
9
|
+
height: 1px;
|
|
10
|
+
padding: 0;
|
|
11
|
+
margin: -1px;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
clip: rect(0, 0, 0, 0);
|
|
14
|
+
white-space: nowrap;
|
|
15
|
+
border: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
.powerhouse-shop {
|
|
2
19
|
--layout-container-max-width: 1400px;
|
|
3
20
|
max-width: var(--layout-container-max-width);
|
|
@@ -94,29 +111,52 @@
|
|
|
94
111
|
align-items: center;
|
|
95
112
|
justify-content: space-between;
|
|
96
113
|
gap: 1rem;
|
|
97
|
-
margin
|
|
114
|
+
margin: 0;
|
|
115
|
+
padding: 1.1rem 1.15rem;
|
|
116
|
+
border-bottom: 1px solid #e8e8e8;
|
|
117
|
+
background: #fff;
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
.powerhouse-shop__sidebar h2,
|
|
101
|
-
.powerhouse-shop__filter
|
|
121
|
+
.powerhouse-shop__filter-toggle {
|
|
102
122
|
margin: 0;
|
|
103
123
|
font-family: var(--font-sans, inherit);
|
|
104
124
|
font-weight: 700;
|
|
125
|
+
color: #1d1d1d;
|
|
105
126
|
}
|
|
106
127
|
|
|
107
128
|
.powerhouse-shop__sidebar h2 {
|
|
108
129
|
font-size: 1.25rem;
|
|
130
|
+
line-height: 1.2;
|
|
109
131
|
}
|
|
110
132
|
|
|
111
133
|
.powerhouse-shop__filter {
|
|
112
|
-
margin: 0
|
|
113
|
-
padding
|
|
114
|
-
border-bottom: 1px solid #
|
|
134
|
+
margin: 0;
|
|
135
|
+
padding: 0;
|
|
136
|
+
border-bottom: 1px solid #e8e8e8;
|
|
115
137
|
}
|
|
116
138
|
|
|
117
|
-
.powerhouse-shop__filter
|
|
118
|
-
|
|
139
|
+
.powerhouse-shop__filter-toggle {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: space-between;
|
|
143
|
+
width: 100%;
|
|
144
|
+
padding: 1.05rem 0 0.85rem;
|
|
145
|
+
border: 0;
|
|
146
|
+
background: transparent;
|
|
119
147
|
font-size: 0.9375rem;
|
|
148
|
+
text-align: left;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.powerhouse-shop__filter-icon {
|
|
153
|
+
font-size: 1.25rem;
|
|
154
|
+
line-height: 1;
|
|
155
|
+
font-weight: 400;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.powerhouse-shop__filter-body {
|
|
159
|
+
padding: 0 0 1.15rem;
|
|
120
160
|
}
|
|
121
161
|
|
|
122
162
|
.powerhouse-shop__filter ul {
|
|
@@ -126,21 +166,21 @@
|
|
|
126
166
|
}
|
|
127
167
|
|
|
128
168
|
.powerhouse-shop__filter li + li {
|
|
129
|
-
margin-top: 0.
|
|
169
|
+
margin-top: 0.7rem;
|
|
130
170
|
}
|
|
131
171
|
|
|
132
172
|
.powerhouse-shop__filter a {
|
|
133
173
|
display: flex;
|
|
134
174
|
align-items: center;
|
|
135
|
-
gap: 0.
|
|
175
|
+
gap: 0.7rem;
|
|
136
176
|
color: #1d1d1d;
|
|
137
177
|
font-size: 0.9375rem;
|
|
138
178
|
text-decoration: none;
|
|
139
179
|
}
|
|
140
180
|
|
|
141
181
|
.powerhouse-shop__check {
|
|
142
|
-
width:
|
|
143
|
-
height:
|
|
182
|
+
width: 1.05rem;
|
|
183
|
+
height: 1.05rem;
|
|
144
184
|
flex-shrink: 0;
|
|
145
185
|
border: 1px solid #1d1d1d;
|
|
146
186
|
background: #fff;
|
|
@@ -151,38 +191,64 @@
|
|
|
151
191
|
box-shadow: inset 0 0 0 2px #fff;
|
|
152
192
|
}
|
|
153
193
|
|
|
194
|
+
.powerhouse-shop__swatches {
|
|
195
|
+
display: flex;
|
|
196
|
+
flex-wrap: wrap;
|
|
197
|
+
gap: 0.55rem;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.powerhouse-shop__swatches li + li {
|
|
201
|
+
margin-top: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.powerhouse-shop__swatch {
|
|
205
|
+
display: block;
|
|
206
|
+
width: 1.35rem;
|
|
207
|
+
height: 1.35rem;
|
|
208
|
+
border: 1px solid #cfcfcf;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.powerhouse-shop__swatches a.is-active .powerhouse-shop__swatch {
|
|
212
|
+
outline: 1px solid #1d1d1d;
|
|
213
|
+
outline-offset: 2px;
|
|
214
|
+
}
|
|
215
|
+
|
|
154
216
|
.powerhouse-shop__price-form {
|
|
155
217
|
display: grid;
|
|
156
218
|
grid-template-columns: 1fr 1fr;
|
|
157
|
-
gap: 0.
|
|
219
|
+
gap: 0.65rem;
|
|
158
220
|
}
|
|
159
221
|
|
|
160
|
-
.powerhouse-shop__price-
|
|
222
|
+
.powerhouse-shop__price-field {
|
|
161
223
|
display: flex;
|
|
162
|
-
|
|
163
|
-
gap: 0.
|
|
164
|
-
|
|
224
|
+
align-items: center;
|
|
225
|
+
gap: 0.35rem;
|
|
226
|
+
min-width: 0;
|
|
227
|
+
padding: 0 0.65rem;
|
|
228
|
+
border: 1px solid #dddddd;
|
|
229
|
+
background: #fff;
|
|
230
|
+
font-size: 0.9375rem;
|
|
231
|
+
color: #6e6e6e;
|
|
165
232
|
}
|
|
166
233
|
|
|
167
|
-
.powerhouse-shop__price-
|
|
168
|
-
.powerhouse-shop__sort select {
|
|
234
|
+
.powerhouse-shop__price-field input {
|
|
169
235
|
width: 100%;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
236
|
+
min-width: 0;
|
|
237
|
+
padding: 0.7rem 0;
|
|
238
|
+
border: 0;
|
|
239
|
+
background: transparent;
|
|
173
240
|
color: #1d1d1d;
|
|
174
241
|
font-family: var(--font-sans, inherit);
|
|
175
242
|
font-size: 0.9375rem;
|
|
176
243
|
}
|
|
177
244
|
|
|
178
|
-
.powerhouse-
|
|
179
|
-
|
|
180
|
-
min-width: 12rem;
|
|
245
|
+
.powerhouse-shop__price-field input:focus {
|
|
246
|
+
outline: none;
|
|
181
247
|
}
|
|
182
248
|
|
|
183
249
|
.powerhouse-shop__price-form button {
|
|
184
250
|
grid-column: 1 / -1;
|
|
185
|
-
padding: 0.
|
|
251
|
+
padding: 0.7rem 0.9rem;
|
|
186
252
|
border: 1px solid #1d1d1d;
|
|
187
253
|
background: #1d1d1d;
|
|
188
254
|
color: #fff;
|
|
@@ -212,37 +278,57 @@
|
|
|
212
278
|
display: flex;
|
|
213
279
|
align-items: center;
|
|
214
280
|
justify-content: space-between;
|
|
215
|
-
gap: 0.
|
|
216
|
-
margin:
|
|
281
|
+
gap: 0.5rem;
|
|
282
|
+
margin: 0.35rem 0 1rem;
|
|
283
|
+
flex-wrap: nowrap;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.powerhouse-shop__utils-left {
|
|
287
|
+
display: flex;
|
|
288
|
+
align-items: center;
|
|
289
|
+
min-width: 0;
|
|
290
|
+
gap: 0.15rem 1.15rem;
|
|
217
291
|
}
|
|
218
292
|
|
|
219
293
|
.powerhouse-shop__filters-btn,
|
|
220
294
|
.powerhouse-shop__sort {
|
|
221
|
-
display: flex;
|
|
295
|
+
display: inline-flex;
|
|
222
296
|
align-items: center;
|
|
223
|
-
gap: 0.
|
|
297
|
+
gap: 0.45rem;
|
|
224
298
|
font-family: var(--font-sans, inherit);
|
|
299
|
+
font-size: 0.9375rem;
|
|
300
|
+
color: #1d1d1d;
|
|
225
301
|
}
|
|
226
302
|
|
|
227
303
|
.powerhouse-shop__filters-btn {
|
|
228
|
-
padding: 0.
|
|
229
|
-
border:
|
|
230
|
-
background:
|
|
231
|
-
color: #1d1d1d;
|
|
304
|
+
padding: 0.45rem 0.15rem;
|
|
305
|
+
border: 0;
|
|
306
|
+
background: transparent;
|
|
232
307
|
cursor: pointer;
|
|
308
|
+
white-space: nowrap;
|
|
233
309
|
}
|
|
234
310
|
|
|
235
|
-
.powerhouse-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
311
|
+
.powerhouse-shop__sort {
|
|
312
|
+
position: relative;
|
|
313
|
+
min-width: 0;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.powerhouse-shop__sort select {
|
|
317
|
+
position: absolute;
|
|
318
|
+
inset: 0;
|
|
319
|
+
width: 100%;
|
|
320
|
+
min-width: 0;
|
|
321
|
+
opacity: 0;
|
|
322
|
+
cursor: pointer;
|
|
242
323
|
}
|
|
243
324
|
|
|
244
325
|
.powerhouse-shop__utils-label {
|
|
245
326
|
font-size: 0.9375rem;
|
|
327
|
+
white-space: nowrap;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.powerhouse-shop__view-label {
|
|
331
|
+
display: none;
|
|
246
332
|
}
|
|
247
333
|
|
|
248
334
|
.powerhouse-shop__view {
|
|
@@ -325,6 +411,7 @@
|
|
|
325
411
|
display: grid;
|
|
326
412
|
grid-template-columns: 7.5rem minmax(0, 1fr);
|
|
327
413
|
align-items: start;
|
|
414
|
+
height: auto;
|
|
328
415
|
gap: 1rem;
|
|
329
416
|
padding: 1.25rem 0;
|
|
330
417
|
border-bottom: 1px solid #dddddd;
|
|
@@ -332,6 +419,18 @@
|
|
|
332
419
|
|
|
333
420
|
.powerhouse-shop__grid.is-list .powerhouse-shop__info {
|
|
334
421
|
padding-top: 0;
|
|
422
|
+
flex: none;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.powerhouse-shop__grid.is-list .powerhouse-shop__name {
|
|
426
|
+
display: block;
|
|
427
|
+
-webkit-line-clamp: unset;
|
|
428
|
+
overflow: visible;
|
|
429
|
+
min-height: 0;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.powerhouse-shop__grid.is-list .powerhouse-shop__price {
|
|
433
|
+
min-height: 0;
|
|
335
434
|
}
|
|
336
435
|
|
|
337
436
|
.powerhouse-shop__grid.is-list .powerhouse-shop__excerpt,
|
|
@@ -351,25 +450,35 @@
|
|
|
351
450
|
.powerhouse-shop__grid {
|
|
352
451
|
display: grid;
|
|
353
452
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
354
|
-
|
|
453
|
+
align-items: stretch;
|
|
454
|
+
gap: 2rem 10px;
|
|
455
|
+
width: 100%;
|
|
355
456
|
}
|
|
356
457
|
|
|
357
458
|
.powerhouse-shop__card {
|
|
459
|
+
display: flex;
|
|
460
|
+
flex-direction: column;
|
|
461
|
+
height: 100%;
|
|
358
462
|
min-width: 0;
|
|
463
|
+
max-width: 100%;
|
|
359
464
|
}
|
|
360
465
|
|
|
361
466
|
.powerhouse-shop__media {
|
|
362
467
|
position: relative;
|
|
363
468
|
display: block;
|
|
469
|
+
width: 100%;
|
|
364
470
|
overflow: hidden;
|
|
365
471
|
background: #f3f3f3;
|
|
472
|
+
aspect-ratio: 1;
|
|
366
473
|
}
|
|
367
474
|
|
|
368
475
|
.powerhouse-shop__media img,
|
|
369
476
|
.powerhouse-shop__placeholder {
|
|
477
|
+
position: absolute;
|
|
478
|
+
inset: 0;
|
|
370
479
|
display: block;
|
|
371
480
|
width: 100%;
|
|
372
|
-
|
|
481
|
+
height: 100%;
|
|
373
482
|
object-fit: cover;
|
|
374
483
|
}
|
|
375
484
|
|
|
@@ -396,15 +505,24 @@
|
|
|
396
505
|
}
|
|
397
506
|
|
|
398
507
|
.powerhouse-shop__info {
|
|
508
|
+
display: flex;
|
|
509
|
+
flex-direction: column;
|
|
510
|
+
flex: 1 1 auto;
|
|
511
|
+
min-width: 0;
|
|
399
512
|
padding-top: 0.75rem;
|
|
400
513
|
}
|
|
401
514
|
|
|
402
515
|
.powerhouse-shop__name {
|
|
516
|
+
display: -webkit-box;
|
|
517
|
+
-webkit-box-orient: vertical;
|
|
518
|
+
-webkit-line-clamp: 2;
|
|
519
|
+
overflow: hidden;
|
|
403
520
|
margin: 0;
|
|
521
|
+
min-height: calc(1em * 1.35 * 2);
|
|
404
522
|
font-family: var(--font-sans, inherit);
|
|
405
523
|
font-size: 1rem;
|
|
406
524
|
font-weight: 400;
|
|
407
|
-
line-height: 1.
|
|
525
|
+
line-height: 1.35;
|
|
408
526
|
}
|
|
409
527
|
|
|
410
528
|
.powerhouse-shop__name a {
|
|
@@ -414,6 +532,7 @@
|
|
|
414
532
|
|
|
415
533
|
.powerhouse-shop__stock {
|
|
416
534
|
margin: 0.35rem 0 0;
|
|
535
|
+
min-height: 1.2em;
|
|
417
536
|
color: #688600;
|
|
418
537
|
font-size: 0.8125rem;
|
|
419
538
|
}
|
|
@@ -431,7 +550,8 @@
|
|
|
431
550
|
}
|
|
432
551
|
|
|
433
552
|
.powerhouse-shop__price {
|
|
434
|
-
margin
|
|
553
|
+
margin: 0 0 0.4rem;
|
|
554
|
+
min-height: 2.7rem;
|
|
435
555
|
}
|
|
436
556
|
|
|
437
557
|
.powerhouse-shop__compare {
|
|
@@ -455,22 +575,26 @@
|
|
|
455
575
|
|
|
456
576
|
.powerhouse-shop__actions {
|
|
457
577
|
display: flex;
|
|
458
|
-
flex-
|
|
459
|
-
|
|
460
|
-
|
|
578
|
+
flex-direction: column;
|
|
579
|
+
flex-wrap: nowrap;
|
|
580
|
+
gap: 0.45rem;
|
|
581
|
+
margin-top: auto;
|
|
582
|
+
padding-top: 0.75rem;
|
|
461
583
|
}
|
|
462
584
|
|
|
463
585
|
.powerhouse-shop__quickshop,
|
|
464
586
|
.powerhouse-shop__atc {
|
|
465
|
-
display:
|
|
587
|
+
display: flex;
|
|
466
588
|
align-items: center;
|
|
467
589
|
justify-content: center;
|
|
590
|
+
width: 100%;
|
|
468
591
|
min-height: 2.5rem;
|
|
469
|
-
padding: 0.5rem 0.
|
|
592
|
+
padding: 0.5rem 0.65rem;
|
|
470
593
|
border-radius: 2px;
|
|
594
|
+
box-sizing: border-box;
|
|
471
595
|
font-family: var(--font-sans, inherit);
|
|
472
|
-
font-size: 0.
|
|
473
|
-
font-weight:
|
|
596
|
+
font-size: 0.875rem;
|
|
597
|
+
font-weight: 600;
|
|
474
598
|
text-decoration: none;
|
|
475
599
|
cursor: pointer;
|
|
476
600
|
}
|
|
@@ -536,40 +660,68 @@
|
|
|
536
660
|
@media screen and (max-width: 859px) {
|
|
537
661
|
.powerhouse-shop.is-filters-open .powerhouse-shop__sidebar,
|
|
538
662
|
.powerhouse-shop__layout.is-filters-open .powerhouse-shop__sidebar {
|
|
539
|
-
display:
|
|
663
|
+
display: flex;
|
|
664
|
+
flex-direction: column;
|
|
540
665
|
position: fixed;
|
|
541
666
|
inset: 0 auto 0 0;
|
|
542
|
-
z-index:
|
|
543
|
-
width: min(
|
|
544
|
-
|
|
545
|
-
|
|
667
|
+
z-index: 80;
|
|
668
|
+
width: min(26.5rem, 100vw);
|
|
669
|
+
max-width: 100%;
|
|
670
|
+
padding: 0;
|
|
671
|
+
overflow: hidden;
|
|
546
672
|
background: #fff;
|
|
547
|
-
box-shadow: 8px 0
|
|
673
|
+
box-shadow: 8px 0 28px rgb(0 0 0 / 18%);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.powerhouse-shop__layout.is-filters-open .powerhouse-shop__sidebar-head {
|
|
677
|
+
position: sticky;
|
|
678
|
+
top: 0;
|
|
679
|
+
z-index: 1;
|
|
680
|
+
flex-shrink: 0;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.powerhouse-shop__layout.is-filters-open .powerhouse-shop__sidebar-body {
|
|
684
|
+
flex: 1;
|
|
685
|
+
min-height: 0;
|
|
686
|
+
overflow: auto;
|
|
687
|
+
padding: 0 1.15rem 2rem;
|
|
688
|
+
-webkit-overflow-scrolling: touch;
|
|
548
689
|
}
|
|
549
690
|
|
|
550
691
|
.powerhouse-shop__layout.is-filters-open .powerhouse-shop__close,
|
|
551
692
|
.powerhouse-shop__layout.is-filters-open .powerhouse-shop__backdrop {
|
|
552
|
-
display:
|
|
693
|
+
display: flex;
|
|
553
694
|
}
|
|
554
695
|
|
|
555
696
|
.powerhouse-shop__backdrop {
|
|
556
697
|
position: fixed;
|
|
557
698
|
inset: 0;
|
|
558
|
-
z-index:
|
|
699
|
+
z-index: 75;
|
|
559
700
|
border: 0;
|
|
560
|
-
background: rgb(0 0 0 /
|
|
701
|
+
background: rgb(0 0 0 / 45%);
|
|
561
702
|
}
|
|
562
703
|
|
|
563
704
|
.powerhouse-shop__close {
|
|
705
|
+
align-items: center;
|
|
706
|
+
justify-content: center;
|
|
707
|
+
width: 2.5rem;
|
|
708
|
+
height: 2.5rem;
|
|
709
|
+
margin-right: -0.45rem;
|
|
564
710
|
padding: 0;
|
|
565
711
|
border: 0;
|
|
566
712
|
background: none;
|
|
567
713
|
color: #1d1d1d;
|
|
568
|
-
text-decoration: underline;
|
|
569
714
|
cursor: pointer;
|
|
570
715
|
}
|
|
571
716
|
}
|
|
572
717
|
|
|
718
|
+
@media screen and (max-width: 719px) {
|
|
719
|
+
.powerhouse-shop__crumbs,
|
|
720
|
+
.powerhouse-shop__masthead {
|
|
721
|
+
display: none;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
573
725
|
@media screen and (min-width: 720px) {
|
|
574
726
|
.powerhouse-shop {
|
|
575
727
|
padding: 0 20px 4rem;
|
|
@@ -593,7 +745,6 @@
|
|
|
593
745
|
}
|
|
594
746
|
|
|
595
747
|
.powerhouse-shop__grid {
|
|
596
|
-
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
597
748
|
gap: 1.75rem 20px;
|
|
598
749
|
}
|
|
599
750
|
|
|
@@ -606,6 +757,13 @@
|
|
|
606
757
|
gap: 1.5rem;
|
|
607
758
|
padding: 1.5rem 0;
|
|
608
759
|
}
|
|
760
|
+
|
|
761
|
+
.powerhouse-shop__sort select {
|
|
762
|
+
position: static;
|
|
763
|
+
opacity: 1;
|
|
764
|
+
width: auto;
|
|
765
|
+
min-width: 10.5rem;
|
|
766
|
+
}
|
|
609
767
|
}
|
|
610
768
|
|
|
611
769
|
@media screen and (min-width: 860px) {
|
|
@@ -621,6 +779,11 @@
|
|
|
621
779
|
flex-shrink: 0;
|
|
622
780
|
}
|
|
623
781
|
|
|
782
|
+
.powerhouse-shop__sidebar-head {
|
|
783
|
+
padding: 0 0 0.85rem;
|
|
784
|
+
border-bottom: 0;
|
|
785
|
+
}
|
|
786
|
+
|
|
624
787
|
.powerhouse-shop__sidebar-head .powerhouse-shop__close,
|
|
625
788
|
.powerhouse-shop__filters-btn {
|
|
626
789
|
display: none;
|
|
@@ -641,10 +804,15 @@
|
|
|
641
804
|
|
|
642
805
|
.powerhouse-shop__utils {
|
|
643
806
|
justify-content: flex-end;
|
|
807
|
+
margin-top: 0.75rem;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.powerhouse-shop__view-label {
|
|
811
|
+
display: inline;
|
|
644
812
|
}
|
|
645
813
|
|
|
646
814
|
.powerhouse-shop__grid {
|
|
647
|
-
grid-template-columns: repeat(
|
|
815
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
648
816
|
}
|
|
649
817
|
|
|
650
818
|
.powerhouse-shop__grid.is-list {
|
|
@@ -668,3 +836,13 @@
|
|
|
668
836
|
pointer-events: auto;
|
|
669
837
|
}
|
|
670
838
|
}
|
|
839
|
+
|
|
840
|
+
@media screen and (min-width: 1100px) {
|
|
841
|
+
.powerhouse-shop__grid {
|
|
842
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.powerhouse-shop__grid.is-list {
|
|
846
|
+
grid-template-columns: 1fr;
|
|
847
|
+
}
|
|
848
|
+
}
|
package/src/shop.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { useEffect, useMemo, useState, type FormEvent } from "react"
|
|
3
|
+
import { useEffect, useMemo, useState, type FormEvent, type ReactNode } from "react"
|
|
4
4
|
import { useRouter } from "next/navigation"
|
|
5
5
|
import LocalizedLink from "@pradip1995/segment-primitives/localized-link"
|
|
6
6
|
import ShopProductCard from "./product-card"
|
|
@@ -87,6 +87,22 @@ function buildParams(props: PowerhouseShopProps, extras: Record<string, string |
|
|
|
87
87
|
return params
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
function FilterIcon() {
|
|
91
|
+
return (
|
|
92
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden>
|
|
93
|
+
<path d="M4 6h16M7 12h10M10 18h4" stroke="currentColor" strokeWidth="1.75" strokeLinecap="square" />
|
|
94
|
+
</svg>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function SortIcon() {
|
|
99
|
+
return (
|
|
100
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" aria-hidden>
|
|
101
|
+
<path d="M8 7V21M8 7L4.5 10.5M8 7L11.5 10.5M16 17V3M16 17L12.5 13.5M16 17L19.5 13.5" stroke="currentColor" strokeWidth="1.75" strokeLinecap="square" />
|
|
102
|
+
</svg>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
function GridIcon() {
|
|
91
107
|
return (
|
|
92
108
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" aria-hidden>
|
|
@@ -157,6 +173,71 @@ function ActiveFilters({
|
|
|
157
173
|
)
|
|
158
174
|
}
|
|
159
175
|
|
|
176
|
+
function colorSwatch(value?: string, label?: string) {
|
|
177
|
+
const raw = (value || label || "").trim()
|
|
178
|
+
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(raw)) return raw
|
|
179
|
+
if (/^(rgb|hsl)a?\(/i.test(raw)) return raw
|
|
180
|
+
const named = raw.toLowerCase().replace(/[\s_-]+/g, "")
|
|
181
|
+
const map: Record<string, string> = {
|
|
182
|
+
black: "#111111",
|
|
183
|
+
white: "#ffffff",
|
|
184
|
+
red: "#c62828",
|
|
185
|
+
blue: "#1565c0",
|
|
186
|
+
green: "#2e7d32",
|
|
187
|
+
yellow: "#f1c40f",
|
|
188
|
+
pink: "#e91e63",
|
|
189
|
+
purple: "#6a1b9a",
|
|
190
|
+
orange: "#ef6c00",
|
|
191
|
+
brown: "#6d4c41",
|
|
192
|
+
grey: "#9e9e9e",
|
|
193
|
+
gray: "#9e9e9e",
|
|
194
|
+
gold: "#c9a86c",
|
|
195
|
+
beige: "#d7ccc8",
|
|
196
|
+
navy: "#1a237e",
|
|
197
|
+
maroon: "#7b1e3a",
|
|
198
|
+
}
|
|
199
|
+
return map[named] || null
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function CloseIcon() {
|
|
203
|
+
return (
|
|
204
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden>
|
|
205
|
+
<path d="M5 5L19 19M19 5L5 19" stroke="currentColor" strokeWidth="1.75" strokeLinecap="square" />
|
|
206
|
+
</svg>
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function FilterSection({
|
|
211
|
+
id,
|
|
212
|
+
title,
|
|
213
|
+
children,
|
|
214
|
+
}: {
|
|
215
|
+
id: string
|
|
216
|
+
title: string
|
|
217
|
+
children: ReactNode
|
|
218
|
+
}) {
|
|
219
|
+
const [open, setOpen] = useState(true)
|
|
220
|
+
return (
|
|
221
|
+
<div className={`powerhouse-shop__filter${open ? " is-open" : ""}`}>
|
|
222
|
+
<button
|
|
223
|
+
type="button"
|
|
224
|
+
className="powerhouse-shop__filter-toggle"
|
|
225
|
+
aria-expanded={open}
|
|
226
|
+
aria-controls={`filter-${id}`}
|
|
227
|
+
onClick={() => setOpen((value) => !value)}
|
|
228
|
+
>
|
|
229
|
+
<span>{title}</span>
|
|
230
|
+
<span className="powerhouse-shop__filter-icon" aria-hidden>
|
|
231
|
+
{open ? "−" : "+"}
|
|
232
|
+
</span>
|
|
233
|
+
</button>
|
|
234
|
+
<div id={`filter-${id}`} className="powerhouse-shop__filter-body" hidden={!open}>
|
|
235
|
+
{children}
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
|
|
160
241
|
const VIEW_STORAGE_KEY = "powerhouse-shop-view"
|
|
161
242
|
|
|
162
243
|
function paginationItems(current: number, total: number) {
|
|
@@ -197,6 +278,19 @@ export default function PowerhouseShop(props: PowerhouseShopProps) {
|
|
|
197
278
|
setView(next)
|
|
198
279
|
}, [])
|
|
199
280
|
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
document.documentElement.classList.toggle("powerhouse-filters-open", filtersOpen)
|
|
283
|
+
if (!filtersOpen) return undefined
|
|
284
|
+
const onKey = (event: KeyboardEvent) => {
|
|
285
|
+
if (event.key === "Escape") setFiltersOpen(false)
|
|
286
|
+
}
|
|
287
|
+
window.addEventListener("keydown", onKey)
|
|
288
|
+
return () => {
|
|
289
|
+
window.removeEventListener("keydown", onKey)
|
|
290
|
+
document.documentElement.classList.remove("powerhouse-filters-open")
|
|
291
|
+
}
|
|
292
|
+
}, [filtersOpen])
|
|
293
|
+
|
|
200
294
|
const categories = (props.categories ?? []).filter((item) => item.id && (item.name || item.handle))
|
|
201
295
|
const collections = (props.collections ?? []).filter((item) => item.id && (item.title || item.handle))
|
|
202
296
|
const types = props.typeOptions?.filter((item) => item.value && item.label) ?? []
|
|
@@ -307,120 +401,142 @@ export default function PowerhouseShop(props: PowerhouseShopProps) {
|
|
|
307
401
|
<aside className="powerhouse-shop__sidebar" aria-label="Filters">
|
|
308
402
|
<div className="powerhouse-shop__sidebar-head">
|
|
309
403
|
<h2>Filters</h2>
|
|
310
|
-
<button
|
|
311
|
-
|
|
404
|
+
<button
|
|
405
|
+
type="button"
|
|
406
|
+
className="powerhouse-shop__close"
|
|
407
|
+
aria-label="Close filters"
|
|
408
|
+
onClick={() => setFiltersOpen(false)}
|
|
409
|
+
>
|
|
410
|
+
<CloseIcon />
|
|
312
411
|
</button>
|
|
313
412
|
</div>
|
|
314
413
|
|
|
315
|
-
<
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
<
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
</
|
|
358
|
-
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
</
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
<
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
414
|
+
<div className="powerhouse-shop__sidebar-body">
|
|
415
|
+
<ActiveFilters filters={applied} clearHref={clearHref} countryCode={countryCode} />
|
|
416
|
+
|
|
417
|
+
{categories.length ? (
|
|
418
|
+
<FilterSection id="product-type" title="Product type">
|
|
419
|
+
<ul>
|
|
420
|
+
{categories.map((item) => {
|
|
421
|
+
const value = item.id
|
|
422
|
+
const selected = activeCategory === value || activeCategory === item.handle
|
|
423
|
+
return (
|
|
424
|
+
<li key={value}>
|
|
425
|
+
<LocalizedLink
|
|
426
|
+
href={toggleFilter(propsWithView, "category", value, selected ? value : undefined)}
|
|
427
|
+
countryCode={countryCode}
|
|
428
|
+
className={selected ? "is-active" : undefined}
|
|
429
|
+
>
|
|
430
|
+
<span className="powerhouse-shop__check" aria-hidden />
|
|
431
|
+
{item.name || item.handle}
|
|
432
|
+
</LocalizedLink>
|
|
433
|
+
</li>
|
|
434
|
+
)
|
|
435
|
+
})}
|
|
436
|
+
</ul>
|
|
437
|
+
</FilterSection>
|
|
438
|
+
) : null}
|
|
439
|
+
|
|
440
|
+
{collections.length ? (
|
|
441
|
+
<FilterSection id="collection" title="Collection">
|
|
442
|
+
<ul>
|
|
443
|
+
{collections.map((item) => {
|
|
444
|
+
const value = item.id
|
|
445
|
+
const selected = activeCollection === value || activeCollection === item.handle
|
|
446
|
+
return (
|
|
447
|
+
<li key={value}>
|
|
448
|
+
<LocalizedLink
|
|
449
|
+
href={toggleFilter(propsWithView, "collection", value, selected ? value : undefined)}
|
|
450
|
+
countryCode={countryCode}
|
|
451
|
+
className={selected ? "is-active" : undefined}
|
|
452
|
+
>
|
|
453
|
+
<span className="powerhouse-shop__check" aria-hidden />
|
|
454
|
+
{item.title || item.handle}
|
|
455
|
+
</LocalizedLink>
|
|
456
|
+
</li>
|
|
457
|
+
)
|
|
458
|
+
})}
|
|
459
|
+
</ul>
|
|
460
|
+
</FilterSection>
|
|
461
|
+
) : null}
|
|
462
|
+
|
|
463
|
+
{types.length ? (
|
|
464
|
+
<FilterSection id="type" title="Type">
|
|
465
|
+
<ul>
|
|
466
|
+
{types.map((item) => {
|
|
467
|
+
const selected = activeType === item.value
|
|
468
|
+
return (
|
|
469
|
+
<li key={item.value}>
|
|
470
|
+
<LocalizedLink
|
|
471
|
+
href={toggleFilter(propsWithView, "type", item.value, selected ? item.value : undefined)}
|
|
472
|
+
countryCode={countryCode}
|
|
473
|
+
className={selected ? "is-active" : undefined}
|
|
474
|
+
>
|
|
475
|
+
<span className="powerhouse-shop__check" aria-hidden />
|
|
476
|
+
{item.label}
|
|
477
|
+
</LocalizedLink>
|
|
478
|
+
</li>
|
|
479
|
+
)
|
|
480
|
+
})}
|
|
481
|
+
</ul>
|
|
482
|
+
</FilterSection>
|
|
483
|
+
) : null}
|
|
484
|
+
|
|
485
|
+
{colors.length ? (
|
|
486
|
+
<FilterSection id="colors" title="Colors">
|
|
487
|
+
<ul className="powerhouse-shop__swatches">
|
|
488
|
+
{colors.map((item) => {
|
|
489
|
+
const selected = activeColor === item.value
|
|
490
|
+
const swatch = colorSwatch(item.value, item.label)
|
|
491
|
+
return (
|
|
492
|
+
<li key={item.value}>
|
|
493
|
+
<LocalizedLink
|
|
494
|
+
href={toggleFilter(propsWithView, "color", item.value, selected ? item.value : undefined)}
|
|
495
|
+
countryCode={countryCode}
|
|
496
|
+
className={selected ? "is-active" : undefined}
|
|
497
|
+
aria-label={item.label}
|
|
498
|
+
>
|
|
499
|
+
{swatch ? (
|
|
500
|
+
<span className="powerhouse-shop__swatch" style={{ background: swatch }} aria-hidden />
|
|
501
|
+
) : (
|
|
502
|
+
<span className="powerhouse-shop__check" aria-hidden />
|
|
503
|
+
)}
|
|
504
|
+
{swatch ? <span className="sr-only">{item.label}</span> : item.label}
|
|
505
|
+
</LocalizedLink>
|
|
506
|
+
</li>
|
|
507
|
+
)
|
|
508
|
+
})}
|
|
509
|
+
</ul>
|
|
510
|
+
</FilterSection>
|
|
511
|
+
) : null}
|
|
512
|
+
|
|
513
|
+
<FilterSection id="price" title="Price">
|
|
514
|
+
<form className="powerhouse-shop__price-form" onSubmit={handlePrice}>
|
|
515
|
+
<label className="powerhouse-shop__price-field">
|
|
516
|
+
<span>₹</span>
|
|
517
|
+
<input
|
|
518
|
+
name="min_price"
|
|
519
|
+
type="number"
|
|
520
|
+
min={0}
|
|
521
|
+
defaultValue={props.minPrice || ""}
|
|
522
|
+
inputMode="decimal"
|
|
523
|
+
placeholder="From"
|
|
524
|
+
/>
|
|
525
|
+
</label>
|
|
526
|
+
<label className="powerhouse-shop__price-field">
|
|
527
|
+
<span>₹</span>
|
|
528
|
+
<input
|
|
529
|
+
name="max_price"
|
|
530
|
+
type="number"
|
|
531
|
+
min={0}
|
|
532
|
+
defaultValue={props.maxPrice || ""}
|
|
533
|
+
inputMode="decimal"
|
|
534
|
+
placeholder="To"
|
|
535
|
+
/>
|
|
536
|
+
</label>
|
|
537
|
+
<button type="submit">Apply</button>
|
|
538
|
+
</form>
|
|
539
|
+
</FilterSection>
|
|
424
540
|
</div>
|
|
425
541
|
</aside>
|
|
426
542
|
|
|
@@ -446,12 +562,14 @@ export default function PowerhouseShop(props: PowerhouseShopProps) {
|
|
|
446
562
|
)}
|
|
447
563
|
|
|
448
564
|
<div className="powerhouse-shop__utils">
|
|
449
|
-
<
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
565
|
+
<div className="powerhouse-shop__utils-left">
|
|
566
|
+
<button type="button" className="powerhouse-shop__filters-btn" onClick={() => setFiltersOpen(true)}>
|
|
567
|
+
<FilterIcon />
|
|
568
|
+
{applied.length ? `Filters (${applied.length})` : "Filters"}
|
|
569
|
+
</button>
|
|
453
570
|
<label className="powerhouse-shop__sort">
|
|
454
|
-
<
|
|
571
|
+
<SortIcon />
|
|
572
|
+
<span className="powerhouse-shop__utils-label">Sort by</span>
|
|
455
573
|
<select value={sortBy} onChange={(event) => handleSort(event.target.value)} aria-label="Sort products">
|
|
456
574
|
{SORT_OPTIONS.map((option) => (
|
|
457
575
|
<option key={option.value} value={option.value}>
|
|
@@ -460,27 +578,27 @@ export default function PowerhouseShop(props: PowerhouseShopProps) {
|
|
|
460
578
|
))}
|
|
461
579
|
</select>
|
|
462
580
|
</label>
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
</
|
|
581
|
+
</div>
|
|
582
|
+
<div className="powerhouse-shop__view" role="group" aria-label="View as">
|
|
583
|
+
<span className="powerhouse-shop__utils-label powerhouse-shop__view-label">View as</span>
|
|
584
|
+
<button
|
|
585
|
+
type="button"
|
|
586
|
+
className={view === "grid" ? "is-active" : undefined}
|
|
587
|
+
aria-label="Grid view"
|
|
588
|
+
aria-pressed={view === "grid"}
|
|
589
|
+
onClick={() => handleView("grid")}
|
|
590
|
+
>
|
|
591
|
+
<GridIcon />
|
|
592
|
+
</button>
|
|
593
|
+
<button
|
|
594
|
+
type="button"
|
|
595
|
+
className={view === "list" ? "is-active" : undefined}
|
|
596
|
+
aria-label="List view"
|
|
597
|
+
aria-pressed={view === "list"}
|
|
598
|
+
onClick={() => handleView("list")}
|
|
599
|
+
>
|
|
600
|
+
<ListIcon />
|
|
601
|
+
</button>
|
|
484
602
|
</div>
|
|
485
603
|
</div>
|
|
486
604
|
|