@o2vend/theme-cli 1.0.36 → 1.0.38
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/README.md +4 -0
- package/lib/lib/dev-server.js +344 -48
- package/lib/lib/liquid-engine.js +3 -1
- package/lib/lib/mock-data.js +473 -119
- package/lib/lib/widget-service.js +12 -4
- package/package.json +2 -2
- package/test-theme/assets/async-sections.js +32 -24
- package/test-theme/assets/cart-drawer.js +20 -22
- package/test-theme/assets/cart-manager.js +1 -15
- package/test-theme/assets/checkout-price-handler.js +12 -11
- package/test-theme/assets/checkout.css +1415 -0
- package/test-theme/assets/checkout.js +3174 -0
- package/test-theme/assets/components.css +178 -29
- package/test-theme/assets/delivery-zone.js +1 -1
- package/test-theme/assets/product-detail.css +1050 -0
- package/test-theme/assets/product-detail.js +2940 -0
- package/test-theme/assets/theme.css +95 -120
- package/test-theme/assets/theme.js +781 -186
- package/test-theme/layout/theme.liquid +91 -17
- package/test-theme/sections/content.liquid +64 -57
- package/test-theme/sections/footer-fallback.liquid +57 -7
- package/test-theme/sections/footer.liquid +63 -12
- package/test-theme/sections/header-fallback.liquid +41 -41
- package/test-theme/sections/header.liquid +41 -51
- package/test-theme/sections/hero-fallback.liquid +1 -1
- package/test-theme/sections/hero.liquid +159 -136
- package/test-theme/snippets/account-sidebar.liquid +121 -29
- package/test-theme/snippets/add-to-cart-modal.liquid +258 -206
- package/test-theme/snippets/breadcrumbs.liquid +98 -11
- package/test-theme/snippets/cart-drawer.liquid +93 -0
- package/test-theme/snippets/delivery-zone-city-selector.liquid +101 -15
- package/test-theme/snippets/delivery-zone-modal.liquid +529 -84
- package/test-theme/snippets/delivery-zone-search.liquid +104 -18
- package/test-theme/snippets/login-modal.liquid +269 -82
- package/test-theme/snippets/mega-menu.liquid +130 -43
- package/test-theme/snippets/news-thumbnail.liquid +120 -28
- package/test-theme/snippets/pagination.liquid +1 -1
- package/test-theme/snippets/price.liquid +100 -9
- package/test-theme/snippets/product-card-related.liquid +22 -4
- package/test-theme/snippets/product-card-simple.liquid +521 -25
- package/test-theme/snippets/product-card.liquid +145 -232
- package/test-theme/snippets/rating.liquid +100 -9
- package/test-theme/snippets/skeleton-collection-grid.liquid +94 -8
- package/test-theme/snippets/skeleton-product-card.liquid +102 -16
- package/test-theme/snippets/skeleton-product-grid.liquid +87 -1
- package/test-theme/snippets/social-sharing.liquid +133 -32
- package/test-theme/templates/account/dashboard.liquid +30 -0
- package/test-theme/templates/account/loyalty-redemption.liquid +29 -28
- package/test-theme/templates/account/loyalty.liquid +45 -43
- package/test-theme/templates/account/order-detail.liquid +15 -8
- package/test-theme/templates/account/orders.liquid +189 -35
- package/test-theme/templates/account/profile.liquid +509 -114
- package/test-theme/templates/account/register.liquid +18 -8
- package/test-theme/templates/account/return-orders.liquid +31 -30
- package/test-theme/templates/account/store-credit.liquid +27 -26
- package/test-theme/templates/account/subscriptions.liquid +22 -5
- package/test-theme/templates/account/wishlist.liquid +88 -19
- package/test-theme/templates/address-book.liquid +166 -69
- package/test-theme/templates/categories.liquid +90 -30
- package/test-theme/templates/checkout.liquid +137 -3834
- package/test-theme/templates/error.liquid +23 -21
- package/test-theme/templates/index.liquid +29 -0
- package/test-theme/templates/login.liquid +33 -6
- package/test-theme/templates/order-confirmation.liquid +67 -9
- package/test-theme/templates/page.liquid +418 -206
- package/test-theme/templates/product-detail.liquid +124 -3878
- package/test-theme/templates/products.liquid +155 -30
- package/test-theme/templates/search.liquid +739 -225
- package/test-theme/widgets/brand-carousel.liquid +102 -82
- package/test-theme/widgets/brand.liquid +78 -50
- package/test-theme/widgets/carousel.liquid +253 -121
- package/test-theme/widgets/category-list-carousel.liquid +32 -8
- package/test-theme/widgets/category-list.liquid +21 -6
- package/test-theme/widgets/category.liquid +104 -37
- package/test-theme/widgets/discount-time.liquid +326 -119
- package/test-theme/widgets/footer-menu.liquid +115 -23
- package/test-theme/widgets/footer.liquid +118 -5
- package/test-theme/widgets/gallery.liquid +29 -5
- package/test-theme/widgets/header-menu.liquid +25 -13
- package/test-theme/widgets/header.liquid +64 -26
- package/test-theme/widgets/html.liquid +29 -6
- package/test-theme/widgets/news.liquid +6 -0
- package/test-theme/widgets/product-canvas.liquid +20 -12
- package/test-theme/widgets/product-carousel.liquid +118 -56
- package/test-theme/widgets/shared/product-grid.liquid +12 -0
- package/test-theme/widgets/single-product.liquid +688 -250
- package/test-theme/widgets/spacebar-carousel.liquid +39 -10
- package/test-theme/widgets/spacebar.liquid +77 -6
- package/test-theme/widgets/splash.liquid +40 -30
- package/test-theme/widgets/testimonial-carousel.liquid +111 -67
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
{% assign image_loading = loading | default: "lazy" %}
|
|
13
13
|
{% assign variants = product.variations | default: empty %}
|
|
14
|
+
{% assign product_call_for_pricing_raw = product.showCallForPricing | default: product.ShowCallForPricing | default: product.isCallForPricing | default: product.IsCallForPricing | default: false %}
|
|
15
|
+
{% assign product_show_call_for_pricing = false %}
|
|
16
|
+
{% if product_call_for_pricing_raw == true or product_call_for_pricing_raw == 'true' or product_call_for_pricing_raw == 1 or product_call_for_pricing_raw == '1' %}
|
|
17
|
+
{% assign product_show_call_for_pricing = true %}
|
|
18
|
+
{% endif %}
|
|
14
19
|
|
|
15
20
|
{% comment %}Calculate default variant for add-to-cart{% endcomment %}
|
|
16
21
|
{% assign defaultVariantForCart = null %}
|
|
@@ -29,6 +34,22 @@
|
|
|
29
34
|
{% endif %}
|
|
30
35
|
{% endif %}
|
|
31
36
|
|
|
37
|
+
{% assign variant_call_for_pricing_raw = defaultVariantForCart.showCallForPricing | default: defaultVariantForCart.ShowCallForPricing | default: defaultVariantForCart.isCallForPricing | default: defaultVariantForCart.IsCallForPricing | default: false %}
|
|
38
|
+
{% assign variant_show_call_for_pricing = false %}
|
|
39
|
+
{% if variant_call_for_pricing_raw == true or variant_call_for_pricing_raw == 'true' or variant_call_for_pricing_raw == 1 or variant_call_for_pricing_raw == '1' %}
|
|
40
|
+
{% assign variant_show_call_for_pricing = true %}
|
|
41
|
+
{% endif %}
|
|
42
|
+
{% assign card_show_call_for_pricing = false %}
|
|
43
|
+
{% if product_show_call_for_pricing or variant_show_call_for_pricing %}
|
|
44
|
+
{% assign card_show_call_for_pricing = true %}
|
|
45
|
+
{% endif %}
|
|
46
|
+
|
|
47
|
+
{% comment %}Product URL (must be set before data attributes){% endcomment %}
|
|
48
|
+
{% assign product_url = product.url | default: product.Url | default: product.link | default: product.Link %}
|
|
49
|
+
{% if product_url == blank %}
|
|
50
|
+
{% assign product_url = product.slug | default: product.id | default: '#' %}
|
|
51
|
+
{% endif %}
|
|
52
|
+
|
|
32
53
|
{% comment %}Image fallback logic{% endcomment %}
|
|
33
54
|
{% assign product_image = nil %}
|
|
34
55
|
{% assign product_image_alt = product.name | default: product.slug | default: product.id %}
|
|
@@ -61,25 +82,27 @@
|
|
|
61
82
|
{% endif %}
|
|
62
83
|
|
|
63
84
|
<div class="product-card"
|
|
64
|
-
data-product-id="{{ product.productId }}"
|
|
85
|
+
data-product-id="{{ product.productId | default: product.id }}"
|
|
65
86
|
data-price="{{ product.prices.price }}"
|
|
87
|
+
data-price-string="{{ product.prices.price | money_with_settings: shop.settings }}"
|
|
66
88
|
data-name="{{ product.name | default: product.slug | default: product.id | downcase }}"
|
|
89
|
+
data-title="{{ product.name | default: product.slug | default: product.id }}"
|
|
90
|
+
data-product-url="{{ product_url }}"
|
|
91
|
+
data-base-product-id="{{ product.productId | default: product.id }}"
|
|
92
|
+
{% if product_image %}data-image="{{ product_image }}"{% endif %}
|
|
93
|
+
data-show-call-for-pricing="{% if card_show_call_for_pricing %}true{% else %}false{% endif %}"
|
|
67
94
|
data-product-type="{{ product.productType | default: product.type | default: 0 }}"
|
|
68
95
|
data-variants-count="{% if variants and variants.size > 0 %}{{ variants.size }}{% else %}0{% endif %}"
|
|
69
|
-
data-availability="{% if product.
|
|
96
|
+
data-availability="{% if product.inStock or product.available %}in-stock{% else %}out-of-stock{% endif %}">
|
|
70
97
|
|
|
71
98
|
<div class="product-card__image-wrapper">
|
|
72
99
|
{% hook 'product_card_image_before' %}
|
|
73
|
-
{
|
|
74
|
-
{% if product_url == blank %}
|
|
75
|
-
{% assign product_url = product.slug | default: product.id | default: '#' %}
|
|
76
|
-
{% endif %}
|
|
77
|
-
<a href="{{ product_url }}" class="product-card__link">
|
|
100
|
+
<a href="/{{ product_url }}" class="product-card__link">
|
|
78
101
|
{% if product_image %}
|
|
79
102
|
<img src="{{ product_image }}"
|
|
80
103
|
alt="{{ product_image_alt }}"
|
|
81
104
|
class="product-card__image"
|
|
82
|
-
loading="{{ image_loading }}">
|
|
105
|
+
loading="{{ image_loading }}" {% if image_fetchpriority %}fetchpriority="{{ image_fetchpriority }}"{% endif %}>
|
|
83
106
|
{% else %}
|
|
84
107
|
<div class="product-card__placeholder">
|
|
85
108
|
<svg class="product-card__placeholder-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
@@ -109,7 +132,7 @@
|
|
|
109
132
|
<span class="product-card__badge product-card__badge--new">New</span>
|
|
110
133
|
{% endif %}
|
|
111
134
|
|
|
112
|
-
{% if product.prices.mrp and product.prices.mrp > product.prices.price %}
|
|
135
|
+
{% if product.prices.mrp and product.prices.mrp > product.prices.price and card_show_call_for_pricing == false %}
|
|
113
136
|
{% assign discount = product.prices.mrp | minus: product.prices.price | times: 100 | divided_by: product.prices.mrp | round %}
|
|
114
137
|
<span class="product-card__badge product-card__badge--sale">-{{ discount }}%</span>
|
|
115
138
|
{% endif %}
|
|
@@ -117,12 +140,28 @@
|
|
|
117
140
|
<span class="product-card__badge product-card__badge--sold-out">Sold Out</span>
|
|
118
141
|
{% endunless %}
|
|
119
142
|
</div>
|
|
143
|
+
|
|
144
|
+
<!-- Product Actions (Wishlist, Quick View) -->
|
|
145
|
+
<div class="product-card__actions">
|
|
146
|
+
<button class="product-action-btn wishlist-btn" data-product-id="{{ product.productId | default: product.id }}" aria-label="Add to wishlist" aria-pressed="false" title="Add to wishlist" tabindex="0">
|
|
147
|
+
<!-- Empty heart by default; theme.js will toggle filled state -->
|
|
148
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
149
|
+
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
|
|
150
|
+
</svg>
|
|
151
|
+
</button>
|
|
152
|
+
<button class="product-action-btn quick-view-btn" data-product-id="{{ product.productId | default: product.id }}" aria-label="Quick view" title="Quick view" tabindex="0">
|
|
153
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
154
|
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
|
|
155
|
+
<circle cx="12" cy="12" r="3"></circle>
|
|
156
|
+
</svg>
|
|
157
|
+
</button>
|
|
158
|
+
</div>
|
|
120
159
|
</div>
|
|
121
160
|
|
|
122
161
|
<div class="product-card__content">
|
|
123
162
|
{% hook 'product_card_title_before' %}
|
|
124
163
|
<h3 class="product-card__title">
|
|
125
|
-
<a href="{{ product_url }}" class="product-card__title-link">
|
|
164
|
+
<a href="/{{ product_url }}" class="product-card__title-link">
|
|
126
165
|
{{ product.name | default: product.slug | default: product.id }}
|
|
127
166
|
</a>
|
|
128
167
|
</h3>
|
|
@@ -130,7 +169,9 @@
|
|
|
130
169
|
|
|
131
170
|
{% hook 'product_card_price_before' %}
|
|
132
171
|
<div class="product-card__price" data-product-card-price="{{ product.productId }}">
|
|
133
|
-
{% if
|
|
172
|
+
{% if card_show_call_for_pricing %}
|
|
173
|
+
<span class="product-card__price-current">Call for pricing</span>
|
|
174
|
+
{% elsif variants and variants.size > 0 %}
|
|
134
175
|
{% assign defaultVariant = null %}
|
|
135
176
|
{% for variant in variants %}
|
|
136
177
|
{% assign isAvailable = variant.inStock | default: variant.available | default: true %}
|
|
@@ -159,7 +200,7 @@
|
|
|
159
200
|
<!-- Add to Cart Button -->
|
|
160
201
|
<button class="product-card__cart-btn add-to-cart-btn"
|
|
161
202
|
data-product-id="{{ defaultVariantProductId }}"
|
|
162
|
-
data-base-product-id="{{ product.productId }}"
|
|
203
|
+
data-base-product-id="{{ product.productId | default: product.id }}"
|
|
163
204
|
data-product-type="{{ product.productType | default: product.type | default: 0 }}"
|
|
164
205
|
{% if variants and variants.size > 0 %}
|
|
165
206
|
{% assign defaultAvailable = defaultVariantForCart.inStock | default: defaultVariantForCart.available | default: true %}
|
|
@@ -187,19 +228,19 @@
|
|
|
187
228
|
<style>
|
|
188
229
|
/* Product Card Variables */
|
|
189
230
|
:root {
|
|
190
|
-
--card-bg: #ffffff;
|
|
191
|
-
--card-border: #e5e7eb;
|
|
192
|
-
--card-shadow: 0 1px 2px rgba(0, 0, 0, 0.
|
|
193
|
-
--card-radius:
|
|
194
|
-
--card-padding:
|
|
195
|
-
--badge-radius:
|
|
196
|
-
--btn-radius:
|
|
197
|
-
--color-primary: #111827;
|
|
198
|
-
--color-secondary: #6b7280;
|
|
199
|
-
--color-sale: #ef4444;
|
|
200
|
-
--color-new: #10b981;
|
|
201
|
-
--color-text: #111827;
|
|
202
|
-
--color-text-muted: #6b7280;
|
|
231
|
+
--card-bg: {{ settings.color_background | default: '#ffffff' }};
|
|
232
|
+
--card-border: {{ settings.color_border | default: '#e5e7eb' }};
|
|
233
|
+
--card-shadow: 0 1px 2px rgba(0, 0, 0, calc({{ settings.shadow_opacity | default: 0.1 }} * 0.5));
|
|
234
|
+
--card-radius: {{ settings.border_radius_medium | default: 8 }}px;
|
|
235
|
+
--card-padding: {{ settings.spacing_element | default: 16 }}px;
|
|
236
|
+
--badge-radius: {{ settings.border_radius_small | default: 4 }}px;
|
|
237
|
+
--btn-radius: {{ settings.border_radius_small | default: 6 }}px;
|
|
238
|
+
--color-primary: {{ settings.color_primary | default: '#111827' }};
|
|
239
|
+
--color-secondary: {{ settings.color_secondary | default: '#6b7280' }};
|
|
240
|
+
--color-sale: {{ settings.color_error | default: '#ef4444' }};
|
|
241
|
+
--color-new: {{ settings.color_success | default: '#10b981' }};
|
|
242
|
+
--color-text: {{ settings.color_text | default: '#111827' }};
|
|
243
|
+
--color-text-muted: {{ settings.color_text_muted | default: '#6b7280' }};
|
|
203
244
|
}
|
|
204
245
|
|
|
205
246
|
/* Card Container */
|
|
@@ -273,6 +314,78 @@
|
|
|
273
314
|
letter-spacing: 0.3px;
|
|
274
315
|
}
|
|
275
316
|
|
|
317
|
+
/* Product action buttons (wishlist, quick view) */
|
|
318
|
+
/* Hidden by default: shown only when hovering/focusing the specific product card */
|
|
319
|
+
.product-card__actions {
|
|
320
|
+
position: absolute;
|
|
321
|
+
top: 10px;
|
|
322
|
+
right: 10px;
|
|
323
|
+
display: flex;
|
|
324
|
+
gap: 8px;
|
|
325
|
+
z-index: 3;
|
|
326
|
+
opacity: 1;
|
|
327
|
+
visibility: visible;
|
|
328
|
+
transform: translateY(0);
|
|
329
|
+
transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
|
|
330
|
+
pointer-events: auto;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* Keep actions visible on all cards so quick view is always available */
|
|
334
|
+
.product-card:hover .product-card__actions,
|
|
335
|
+
.product-card:focus-within .product-card__actions {
|
|
336
|
+
opacity: 1;
|
|
337
|
+
visibility: visible;
|
|
338
|
+
transform: translateY(0);
|
|
339
|
+
pointer-events: auto;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.product-action-btn {
|
|
343
|
+
border: none;
|
|
344
|
+
background: rgba(255,255,255,0.92);
|
|
345
|
+
width: 36px;
|
|
346
|
+
height: 36px;
|
|
347
|
+
border-radius: 50%;
|
|
348
|
+
display: inline-flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
justify-content: center;
|
|
351
|
+
cursor: pointer;
|
|
352
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
353
|
+
transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease, opacity 0.12s ease;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.product-action-btn:hover {
|
|
357
|
+
transform: translateY(-2px);
|
|
358
|
+
box-shadow: 0 6px 20px rgba(0,0,0,0.12);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* Ensure svg sizing still applies */
|
|
362
|
+
.product-action-btn svg {
|
|
363
|
+
width: 18px;
|
|
364
|
+
height: 18px;
|
|
365
|
+
color: #111827;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* On touch devices (no hover), keep actions visible for accessibility */
|
|
369
|
+
@media (hover: none) and (pointer: coarse) {
|
|
370
|
+
.product-card__actions {
|
|
371
|
+
opacity: 1;
|
|
372
|
+
visibility: visible;
|
|
373
|
+
transform: translateY(0);
|
|
374
|
+
pointer-events: auto;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* Wishlist active state */
|
|
379
|
+
.wishlist-btn.in-wishlist {
|
|
380
|
+
background: rgba(239, 68, 68, 0.95);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.wishlist-btn.in-wishlist svg {
|
|
384
|
+
fill: #ffffff;
|
|
385
|
+
stroke: #ffffff;
|
|
386
|
+
color: #ffffff;
|
|
387
|
+
}
|
|
388
|
+
|
|
276
389
|
.product-card__badge--new {
|
|
277
390
|
background: var(--color-new);
|
|
278
391
|
color: white;
|
|
@@ -347,7 +460,7 @@
|
|
|
347
460
|
font-weight: 500;
|
|
348
461
|
cursor: pointer;
|
|
349
462
|
margin-top: auto;
|
|
350
|
-
border-radius: var(--
|
|
463
|
+
border-radius: var(--card-radius);
|
|
351
464
|
border: none;
|
|
352
465
|
}
|
|
353
466
|
|
|
@@ -391,10 +504,10 @@
|
|
|
391
504
|
/* Mobile */
|
|
392
505
|
@media screen and (max-width: 768px) {
|
|
393
506
|
:root {
|
|
394
|
-
--card-radius:
|
|
395
|
-
--card-padding:
|
|
396
|
-
--badge-radius:
|
|
397
|
-
--btn-radius:
|
|
507
|
+
--card-radius: {{ settings.border_radius_small | default: 6 }}px;
|
|
508
|
+
--card-padding: {{ settings.spacing_small | default: 10 }}px;
|
|
509
|
+
--badge-radius: {{ settings.border_radius_small | default: 3 }}px;
|
|
510
|
+
--btn-radius: {{ settings.border_radius_small | default: 5 }}px;
|
|
398
511
|
}
|
|
399
512
|
|
|
400
513
|
.product-card {
|
|
@@ -477,7 +590,7 @@
|
|
|
477
590
|
</style>
|
|
478
591
|
|
|
479
592
|
{% if variants and variants.size > 0 %}
|
|
480
|
-
<script type="application/json" class="product-card-variant-data" data-product-id="{{ product.productId }}">
|
|
593
|
+
<script type="application/json" class="product-card-variant-data" data-product-id="{{ product.productId | default: product.id }}">
|
|
481
594
|
{
|
|
482
595
|
"variants": [
|
|
483
596
|
{% for variant in variants %}
|
|
@@ -490,208 +603,8 @@
|
|
|
490
603
|
}{% unless forloop.last %},{% endunless %}
|
|
491
604
|
{% endfor %}
|
|
492
605
|
],
|
|
493
|
-
"baseProductId": {{ product.productId }}
|
|
606
|
+
"baseProductId": {{ product.productId | default: product.id }}
|
|
494
607
|
}
|
|
495
608
|
</script>
|
|
496
609
|
{% endif %}
|
|
497
610
|
|
|
498
|
-
<script>
|
|
499
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
500
|
-
const productCards = document.querySelectorAll('.product-card');
|
|
501
|
-
|
|
502
|
-
productCards.forEach(card => {
|
|
503
|
-
initializeProductCard(card);
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
function initializeProductCard(card) {
|
|
507
|
-
const cartBtn = card.querySelector('.product-card__cart-btn');
|
|
508
|
-
if (cartBtn) {
|
|
509
|
-
const productType = parseInt(card.dataset.productType || cartBtn.dataset.productType || '0', 10);
|
|
510
|
-
const variantsCount = parseInt(card.dataset.variantsCount || '0', 10);
|
|
511
|
-
|
|
512
|
-
if (productType === 0 && variantsCount === 0) {
|
|
513
|
-
cartBtn.addEventListener('click', function(e) {
|
|
514
|
-
e.preventDefault();
|
|
515
|
-
e.stopPropagation();
|
|
516
|
-
handleAddToCart(this, card);
|
|
517
|
-
}, true);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
function handleAddToCart(button, card) {
|
|
523
|
-
if (button.disabled) return;
|
|
524
|
-
|
|
525
|
-
const productId = button.getAttribute('data-product-id');
|
|
526
|
-
const originalText = button.querySelector('.product-card__cart-text')?.textContent || 'Add to Cart';
|
|
527
|
-
|
|
528
|
-
if (button.querySelector('.product-card__cart-text')) {
|
|
529
|
-
button.querySelector('.product-card__cart-text').textContent = 'Adding...';
|
|
530
|
-
}
|
|
531
|
-
button.disabled = true;
|
|
532
|
-
|
|
533
|
-
addToCartAPI(productId)
|
|
534
|
-
.then(response => {
|
|
535
|
-
if (button.querySelector('.product-card__cart-text')) {
|
|
536
|
-
button.querySelector('.product-card__cart-text').textContent = '✓ Added';
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
updateHeaderCart();
|
|
540
|
-
|
|
541
|
-
// Unified bottom-center toast confirmation
|
|
542
|
-
if (window.Theme && typeof window.Theme.showNotification === 'function') {
|
|
543
|
-
window.Theme.showNotification('Product added to cart!', 'success', 3000);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
setTimeout(() => {
|
|
547
|
-
if (button.querySelector('.product-card__cart-text')) {
|
|
548
|
-
button.querySelector('.product-card__cart-text').textContent = originalText;
|
|
549
|
-
}
|
|
550
|
-
button.disabled = false;
|
|
551
|
-
}, 2000);
|
|
552
|
-
})
|
|
553
|
-
.catch(error => {
|
|
554
|
-
console.error('Add to cart error:', error);
|
|
555
|
-
|
|
556
|
-
// Check if error message indicates authentication is required
|
|
557
|
-
// This handles cases where the error object might have requiresAuth info
|
|
558
|
-
if (error.message && error.message.includes('Authentication required')) {
|
|
559
|
-
// Try to open login modal
|
|
560
|
-
if (window.Theme && window.Theme.openLoginModal) {
|
|
561
|
-
window.Theme.openLoginModal();
|
|
562
|
-
} else if (window.CartManager && window.CartManager.openLoginModal) {
|
|
563
|
-
window.CartManager.openLoginModal();
|
|
564
|
-
} else {
|
|
565
|
-
const loginTrigger = document.querySelector('[data-login-modal-trigger]');
|
|
566
|
-
if (loginTrigger) {
|
|
567
|
-
loginTrigger.click();
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
} else {
|
|
571
|
-
// Show error message
|
|
572
|
-
if (button.querySelector('.product-card__cart-text')) {
|
|
573
|
-
button.querySelector('.product-card__cart-text').textContent = 'Error';
|
|
574
|
-
}
|
|
575
|
-
// Unified error toast
|
|
576
|
-
if (window.Theme && typeof window.Theme.showNotification === 'function') {
|
|
577
|
-
window.Theme.showNotification('Failed to add product to cart. Please try again.', 'error', 3000);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
setTimeout(() => {
|
|
582
|
-
if (button.querySelector('.product-card__cart-text')) {
|
|
583
|
-
button.querySelector('.product-card__cart-text').textContent = originalText;
|
|
584
|
-
}
|
|
585
|
-
button.disabled = false;
|
|
586
|
-
}, 2000);
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
function addToCartAPI(productId) {
|
|
591
|
-
return fetch('/webstoreapi/carts/add', {
|
|
592
|
-
method: 'POST',
|
|
593
|
-
headers: {
|
|
594
|
-
'Content-Type': 'application/json',
|
|
595
|
-
'Accept': 'application/json'
|
|
596
|
-
},
|
|
597
|
-
body: JSON.stringify({
|
|
598
|
-
productId: productId,
|
|
599
|
-
quantity: 1
|
|
600
|
-
})
|
|
601
|
-
})
|
|
602
|
-
.then(response => response.json())
|
|
603
|
-
.then(data => {
|
|
604
|
-
if (data.success) {
|
|
605
|
-
return data;
|
|
606
|
-
} else {
|
|
607
|
-
// Check if authentication is required
|
|
608
|
-
if (data.requiresAuth) {
|
|
609
|
-
// Try to open login modal from Theme instance
|
|
610
|
-
if (window.Theme && window.Theme.openLoginModal) {
|
|
611
|
-
window.Theme.openLoginModal();
|
|
612
|
-
} else if (window.CartManager && window.CartManager.openLoginModal) {
|
|
613
|
-
window.CartManager.openLoginModal();
|
|
614
|
-
} else {
|
|
615
|
-
// Fallback: trigger login modal via data attribute
|
|
616
|
-
const loginTrigger = document.querySelector('[data-login-modal-trigger]');
|
|
617
|
-
if (loginTrigger) {
|
|
618
|
-
loginTrigger.click();
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
throw new Error('Authentication required');
|
|
622
|
-
}
|
|
623
|
-
throw new Error(data.error || data.message || 'Failed to add to cart');
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
function updateHeaderCart() {
|
|
629
|
-
if (window.CartManager && typeof window.CartManager.getCartCount === 'function') {
|
|
630
|
-
window.CartManager.getCartCount()
|
|
631
|
-
.then(count => {
|
|
632
|
-
updateCartBadge(count);
|
|
633
|
-
})
|
|
634
|
-
.catch(error => {
|
|
635
|
-
fetchCartFromAPI();
|
|
636
|
-
});
|
|
637
|
-
} else {
|
|
638
|
-
fetchCartFromAPI();
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
function fetchCartFromAPI() {
|
|
642
|
-
fetch('/webstoreapi/cart', {
|
|
643
|
-
method: 'GET',
|
|
644
|
-
headers: {
|
|
645
|
-
'Accept': 'application/json',
|
|
646
|
-
'X-Requested-With': 'XMLHttpRequest'
|
|
647
|
-
}
|
|
648
|
-
})
|
|
649
|
-
.then(response => response.json())
|
|
650
|
-
.then(data => {
|
|
651
|
-
if (data.success && data.cart) {
|
|
652
|
-
const itemCount = data.cart.itemCount || data.cart.cartQuantity || (data.cart.items ? data.cart.items.length : 0) || 0;
|
|
653
|
-
updateCartBadge(itemCount);
|
|
654
|
-
} else {
|
|
655
|
-
updateCartBadge(0);
|
|
656
|
-
}
|
|
657
|
-
})
|
|
658
|
-
.catch(error => {
|
|
659
|
-
console.error('Error updating header cart:', error);
|
|
660
|
-
updateCartBadge(0);
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
function updateCartBadge(count) {
|
|
665
|
-
const itemCount = parseInt(count, 10) || 0;
|
|
666
|
-
|
|
667
|
-
const cartCountElements = document.querySelectorAll('.site-header__cart-count, [data-cart-count]');
|
|
668
|
-
cartCountElements.forEach(el => {
|
|
669
|
-
el.textContent = itemCount;
|
|
670
|
-
el.setAttribute('data-cart-count', itemCount.toString());
|
|
671
|
-
el.style.display = itemCount > 0 ? 'flex' : 'none';
|
|
672
|
-
});
|
|
673
|
-
|
|
674
|
-
if (window.CartManager && typeof window.CartManager.updateCartBadge === 'function') {
|
|
675
|
-
window.CartManager.updateCartBadge(itemCount);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
const event = new CustomEvent('cart:updated', {
|
|
679
|
-
detail: { count: itemCount }
|
|
680
|
-
});
|
|
681
|
-
document.dispatchEvent(event);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
function initCartUpdate() {
|
|
686
|
-
setTimeout(() => {
|
|
687
|
-
updateHeaderCart();
|
|
688
|
-
}, 100);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (document.readyState === 'loading') {
|
|
692
|
-
document.addEventListener('DOMContentLoaded', initCartUpdate);
|
|
693
|
-
} else {
|
|
694
|
-
initCartUpdate();
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
</script>
|
|
@@ -48,38 +48,129 @@
|
|
|
48
48
|
</div>
|
|
49
49
|
|
|
50
50
|
<style>
|
|
51
|
+
:root {
|
|
52
|
+
--color-primary: {{ settings.color_primary | default: '#000000' }};
|
|
53
|
+
--color-primary-hover: {{ settings.color_primary_dark | default: '#333333' }};
|
|
54
|
+
--color-primary-light: {{ settings.color_primary_light | default: '#666666' }};
|
|
55
|
+
--color-success: {{ settings.color_success | default: '#22c55e' }};
|
|
56
|
+
--color-success-light: {{ settings.color_success | default: '#22c55e' }};
|
|
57
|
+
--color-success-dark: {{ settings.color_success | default: '#22c55e' }};
|
|
58
|
+
--color-danger: {{ settings.color_error | default: '#ef4444' }};
|
|
59
|
+
--color-danger-light: {{ settings.color_error | default: '#ef4444' }};
|
|
60
|
+
--color-danger-dark: {{ settings.color_error | default: '#ef4444' }};
|
|
61
|
+
--color-text: {{ settings.color_text | default: '#000000' }};
|
|
62
|
+
--color-text-light: {{ settings.color_text_light | default: '#999999' }};
|
|
63
|
+
--color-text-muted: {{ settings.color_text_muted | default: '#666666' }};
|
|
64
|
+
--color-background: {{ settings.color_background | default: '#ffffff' }};
|
|
65
|
+
--color-card-bg: {{ settings.color_surface | default: '#f5f5f5' }};
|
|
66
|
+
--color-border: {{ settings.color_border | default: '#cccccc' }};
|
|
67
|
+
--color-border-light: {{ settings.color_surface | default: '#f5f5f5' }};
|
|
68
|
+
--color-white: #ffffff;
|
|
69
|
+
--color-black: {{ settings.color_primary_dark | default: '#333333' }};
|
|
70
|
+
--color-gray-25: {{ settings.color_background | default: '#ffffff' }};
|
|
71
|
+
--color-gray-50: {{ settings.color_surface | default: '#f5f5f5' }};
|
|
72
|
+
--color-gray-100: {{ settings.color_surface | default: '#f5f5f5' }};
|
|
73
|
+
--color-gray-200: {{ settings.color_border | default: '#cccccc' }};
|
|
74
|
+
--color-gray-300: {{ settings.color_border | default: '#cccccc' }};
|
|
75
|
+
--color-gray-400: {{ settings.color_text_muted | default: '#666666' }};
|
|
76
|
+
--color-gray-500: {{ settings.color_text_muted | default: '#666666' }};
|
|
77
|
+
--color-gray-600: {{ settings.color_text_muted | default: '#666666' }};
|
|
78
|
+
--color-gray-700: {{ settings.color_text | default: '#000000' }};
|
|
79
|
+
--color-gray-800: {{ settings.color_text | default: '#000000' }};
|
|
80
|
+
--color-gray-900: {{ settings.color_text | default: '#000000' }};
|
|
81
|
+
/* Shadow variables - mapped from settings */
|
|
82
|
+
--shadow-opacity: {{ settings.shadow_opacity | default: 0.1 }};
|
|
83
|
+
--shadow-blur: {{ settings.shadow_blur | default: 8 }}px;
|
|
84
|
+
--shadow-spread: {{ settings.shadow_spread | default: 0 }}px;
|
|
85
|
+
|
|
86
|
+
/* Border radius - mapped from settings */
|
|
87
|
+
--radius-sm: {{ settings.border_radius_small | default: 6 }}px;
|
|
88
|
+
--radius-md: {{ settings.border_radius_medium | default: 10 }}px;
|
|
89
|
+
--radius-lg: {{ settings.border_radius_large | default: 16 }}px;
|
|
90
|
+
--radius-xl: 24px;
|
|
91
|
+
--radius-2xl: 32px;
|
|
92
|
+
--radius-full: 9999px;
|
|
93
|
+
|
|
94
|
+
/* Spacing - mapped from settings */
|
|
95
|
+
--spacing-xs: {{ settings.spacing_xsmall | default: 4 }}px;
|
|
96
|
+
--spacing-sm: {{ settings.spacing_small | default: 8 }}px;
|
|
97
|
+
--spacing-md: {{ settings.spacing_element | default: 16 }}px;
|
|
98
|
+
--spacing-lg: {{ settings.spacing_component | default: 24 }}px;
|
|
99
|
+
--spacing-xl: {{ settings.spacing_large | default: 32 }}px;
|
|
100
|
+
|
|
101
|
+
/* Typography - mapped from settings */
|
|
102
|
+
--font-primary: {{ settings.font_primary | default: '' }}, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
|
|
103
|
+
--font-heading: {{ settings.font_heading | default: '' }}, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
|
|
104
|
+
--font-display: {{ settings.font_display | default: '' }}, 'Georgia', 'Times New Roman', serif;
|
|
105
|
+
--font-body: {{ settings.font_body | default: '' }}, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
|
|
106
|
+
--font-weight-bold: {{ settings.font_weight_bold | default: 700 }};
|
|
107
|
+
--font-weight-medium: {{ settings.font_weight_medium | default: 500 }};
|
|
108
|
+
--line-height-heading: {{ settings.line_height_heading | default: 1.2 }};
|
|
109
|
+
|
|
110
|
+
/* Text sizes - based on font_size_base from settings */
|
|
111
|
+
--text-xs: 12px;
|
|
112
|
+
--text-sm: {{ settings.font_size_base | default: 14 }}px;
|
|
113
|
+
--text-base: {{ settings.font_size_base | default: 14 }}px;
|
|
114
|
+
--text-lg: 16px;
|
|
115
|
+
--text-xl: 18px;
|
|
116
|
+
--text-2xl: 21px;
|
|
117
|
+
|
|
118
|
+
/* Transitions - mapped from settings */
|
|
119
|
+
--transition-fast: 133ms cubic-bezier(0, 0, 0.2, 1);
|
|
120
|
+
--transition: {{ settings.button_transition_speed | default: 200 }}ms cubic-bezier(0, 0, 0.2, 1);
|
|
121
|
+
--transition-slow: 300ms cubic-bezier(0, 0, 0.2, 1);
|
|
122
|
+
--duration-150: 150ms;
|
|
123
|
+
--duration-300: 300ms;
|
|
124
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
125
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
126
|
+
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
127
|
+
|
|
128
|
+
/* Z-index values */
|
|
129
|
+
--z-10: 10;
|
|
130
|
+
--z-modal: 1050;
|
|
131
|
+
--z-dropdown: 1000;
|
|
132
|
+
|
|
133
|
+
/* Line heights - mapped from settings */
|
|
134
|
+
--leading-none: 1;
|
|
135
|
+
--leading-normal: {{ settings.line_height_base | default: 1.6 }};
|
|
136
|
+
--leading-snug: 1.375;
|
|
137
|
+
|
|
138
|
+
/* Letter spacing - mapped from settings */
|
|
139
|
+
--tracking-wider: {{ settings.letter_spacing_uppercase | default: 0.05 }}em;
|
|
140
|
+
}
|
|
141
|
+
|
|
51
142
|
.rating {
|
|
52
143
|
display: flex;
|
|
53
144
|
align-items: center;
|
|
54
|
-
gap:
|
|
145
|
+
gap: var(--space-2);
|
|
55
146
|
}
|
|
56
147
|
|
|
57
148
|
.rating-stars {
|
|
58
149
|
display: inline-flex;
|
|
59
|
-
gap: 0
|
|
60
|
-
font-size:
|
|
61
|
-
line-height:
|
|
150
|
+
gap: var(--space-0-5);
|
|
151
|
+
font-size: var(--text-base);
|
|
152
|
+
line-height: var(--leading-none);
|
|
62
153
|
}
|
|
63
154
|
|
|
64
155
|
.rating-star {
|
|
65
156
|
color: #fbbf24;
|
|
66
|
-
font-size:
|
|
157
|
+
font-size: var(--text-base);
|
|
67
158
|
}
|
|
68
159
|
|
|
69
160
|
.rating-star-empty {
|
|
70
|
-
color:
|
|
161
|
+
color: var(--color-gray-200);
|
|
71
162
|
}
|
|
72
163
|
|
|
73
164
|
.rating-star-half {
|
|
74
|
-
background: linear-gradient(90deg, #fbbf24 50%,
|
|
165
|
+
background: linear-gradient(90deg, #fbbf24 50%, var(--color-gray-200) 50%);
|
|
75
166
|
-webkit-background-clip: text;
|
|
76
167
|
-webkit-text-fill-color: transparent;
|
|
77
168
|
background-clip: text;
|
|
78
169
|
}
|
|
79
170
|
|
|
80
171
|
.rating-count {
|
|
81
|
-
font-size:
|
|
82
|
-
color:
|
|
172
|
+
font-size: var(--text-sm);
|
|
173
|
+
color: var(--color-text-light);
|
|
83
174
|
}
|
|
84
175
|
</style>
|
|
85
176
|
|