@runwell/shopify-toolkit 0.17.4 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/runwell-shopify +14 -2
- package/lib/list.js +133 -0
- package/lib/qa-bundles.js +117 -0
- package/lib/qa.js +147 -13
- package/modules/INDEX.md +65 -23
- package/modules/_shared/css-tokens/assets/runwell-tokens.css +24 -4
- package/modules/_shared/css-tokens/module.json +2 -2
- package/modules/_shared/css-typography/assets/runwell-typography.css +14 -6
- package/modules/_shared/css-typography/module.json +2 -2
- package/modules/bundle-builder/README.md +6 -1
- package/modules/bundle-builder/module.json +5 -1
- package/modules/care-coaching-medvi/README.md +46 -0
- package/modules/care-coaching-medvi/assets/runwell-care-coaching-medvi.css +241 -0
- package/modules/care-coaching-medvi/module.json +80 -0
- package/modules/care-coaching-medvi/sections/runwell-care-coaching-medvi.liquid +274 -0
- package/modules/care-coaching-medvi/snippets/runwell-care-coaching-medvi-circular-text.liquid +25 -0
- package/modules/cart-cross-sell/snippets/runwell-cart-xsell.liquid +16 -0
- package/modules/collection-block-medvi/README.md +50 -0
- package/modules/collection-block-medvi/assets/runwell-collection-block-medvi.css +242 -0
- package/modules/collection-block-medvi/module.json +83 -0
- package/modules/collection-block-medvi/sections/runwell-collection-block-medvi.liquid +355 -0
- package/modules/product-trio-medvi/README.md +35 -0
- package/modules/product-trio-medvi/assets/runwell-product-trio-medvi.css +119 -0
- package/modules/product-trio-medvi/module.json +48 -0
- package/modules/product-trio-medvi/sections/runwell-product-trio-medvi.liquid +188 -0
- package/modules/runwell-bundle-system/README.md +35 -0
- package/modules/runwell-bundle-system/admin-metafields.json +46 -0
- package/modules/runwell-bundle-system/assets/runwell-bundle-system.css +861 -0
- package/modules/runwell-bundle-system/assets/runwell-bundle-system.js +287 -0
- package/modules/runwell-bundle-system/module.json +126 -0
- package/modules/runwell-bundle-system/qa/mobile-checklist.md +105 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-cart-xsell.liquid +59 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-collection.liquid +121 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-home-stacks.liquid +77 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-pdp-banner.liquid +50 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-pdp-pairs-with.liquid +72 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-pdp.liquid +105 -0
- package/modules/runwell-bundle-system/settings.json +25 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-card.liquid +70 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-cross-supplier.liquid +18 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-data.liquid +67 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-fomo.liquid +32 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-free-gift.liquid +34 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-multi-product.liquid +86 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-pricing.liquid +30 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-quantity-tiers.liquid +73 -0
- package/modules/testimonials-medvi/README.md +44 -0
- package/modules/testimonials-medvi/assets/runwell-testimonials-medvi.css +239 -0
- package/modules/testimonials-medvi/module.json +68 -0
- package/modules/testimonials-medvi/sections/runwell-testimonials-medvi.liquid +355 -0
- package/package.json +2 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-collection.liquid.
|
|
3
|
+
Shared by Surface 1 (/bundles dedicated page, mode 'grid') and
|
|
4
|
+
Surface 6 (collection-page bundles filter chip, mode 'filter_chip').
|
|
5
|
+
|
|
6
|
+
Bundle detection: prefers products with the runwell.bundle_mode
|
|
7
|
+
metafield set; falls back to products tagged 'bundle'.
|
|
8
|
+
|
|
9
|
+
See _clients/capital-v/lushi/specs/bundle-system/spec.md sections 5, 8.1, 8.6.
|
|
10
|
+
{%- endcomment -%}
|
|
11
|
+
|
|
12
|
+
{%- assign mode = section.settings.mode | default: 'grid' -%}
|
|
13
|
+
|
|
14
|
+
{%- comment -%} Build the bundles list from collection.products if present, otherwise scan all_products. {%- endcomment -%}
|
|
15
|
+
{%- assign source_products = collection.products -%}
|
|
16
|
+
{%- if source_products == blank or source_products.size == 0 -%}
|
|
17
|
+
{%- assign source_products = all_products -%}
|
|
18
|
+
{%- endif -%}
|
|
19
|
+
|
|
20
|
+
{%- assign bundles_meta = source_products | where: 'metafields.runwell.bundle_mode' -%}
|
|
21
|
+
{%- assign bundles = bundles_meta -%}
|
|
22
|
+
{%- if bundles == empty or bundles.size == 0 -%}
|
|
23
|
+
{%- assign bundles = source_products | where: 'tags', 'bundle' -%}
|
|
24
|
+
{%- endif -%}
|
|
25
|
+
|
|
26
|
+
{%- if mode == 'grid' -%}
|
|
27
|
+
{%- if settings.bundle_system__surface_1_collection_page_enabled == false -%}
|
|
28
|
+
{%- comment -%} Tenant has disabled the /bundles page surface. {%- endcomment -%}
|
|
29
|
+
{%- else -%}
|
|
30
|
+
<section
|
|
31
|
+
class="runwell-bundle-collection runwell-bundle-collection--grid color-{{ section.settings.color_scheme }}"
|
|
32
|
+
style="padding-top: {{ section.settings.padding_top }}px; padding-bottom: {{ section.settings.padding_bottom }}px;"
|
|
33
|
+
>
|
|
34
|
+
<div class="runwell-bundle-collection__inner page-width">
|
|
35
|
+
{%- if section.settings.show_heading -%}
|
|
36
|
+
<header class="runwell-bundle-collection__heading">
|
|
37
|
+
<h1 class="runwell-bundle-collection__title">{{ section.settings.title }}</h1>
|
|
38
|
+
{%- if section.settings.subline != blank -%}
|
|
39
|
+
<p class="runwell-bundle-collection__subline">{{ section.settings.subline }}</p>
|
|
40
|
+
{%- endif -%}
|
|
41
|
+
</header>
|
|
42
|
+
{%- endif -%}
|
|
43
|
+
|
|
44
|
+
<div class="runwell-bundle-collection__grid">
|
|
45
|
+
{%- for bundle_product in bundles -%}
|
|
46
|
+
{%- assign card_variant = 'default' -%}
|
|
47
|
+
{%- if forloop.first and section.settings.feature_first_bundle -%}
|
|
48
|
+
{%- assign card_variant = 'hero' -%}
|
|
49
|
+
{%- endif -%}
|
|
50
|
+
{% render 'runwell-bundle-card', bundle_product: bundle_product, variant: card_variant %}
|
|
51
|
+
{%- else -%}
|
|
52
|
+
<p class="runwell-bundle-collection__empty">
|
|
53
|
+
No bundles configured yet. Add the <code>bundle</code> tag to a product or set the <code>runwell.bundle_mode</code> metafield to surface it here.
|
|
54
|
+
</p>
|
|
55
|
+
{%- endfor -%}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
{%- endif -%}
|
|
60
|
+
|
|
61
|
+
{%- elsif mode == 'filter_chip' -%}
|
|
62
|
+
{%- if settings.bundle_system__surface_6_collection_filter_enabled == false -%}
|
|
63
|
+
{%- comment -%} Tenant has not enabled the collection-page filter surface. {%- endcomment -%}
|
|
64
|
+
{%- else -%}
|
|
65
|
+
{%- if bundles and bundles.size > 0 -%}
|
|
66
|
+
<section
|
|
67
|
+
class="runwell-bundle-collection runwell-bundle-collection--filter-chip"
|
|
68
|
+
data-bundle-handles="{%- for b in bundles -%}{{ b.handle }}{%- unless forloop.last -%},{%- endunless -%}{%- endfor -%}"
|
|
69
|
+
>
|
|
70
|
+
<button class="runwell-bundle-collection__chip" data-runwell-bundle-filter-chip aria-pressed="false">
|
|
71
|
+
{{ section.settings.chip_label | default: 'Bundles' }}
|
|
72
|
+
<span class="runwell-bundle-collection__chip-count">({{ bundles.size }})</span>
|
|
73
|
+
</button>
|
|
74
|
+
<div class="runwell-bundle-collection__pinned">
|
|
75
|
+
{%- for bundle_product in bundles limit: 2 -%}
|
|
76
|
+
{% render 'runwell-bundle-card', bundle_product: bundle_product, variant: 'compact' %}
|
|
77
|
+
{%- endfor -%}
|
|
78
|
+
</div>
|
|
79
|
+
</section>
|
|
80
|
+
{%- endif -%}
|
|
81
|
+
{%- endif -%}
|
|
82
|
+
{%- endif -%}
|
|
83
|
+
|
|
84
|
+
{{ 'runwell-bundle-system.css' | asset_url | stylesheet_tag }}
|
|
85
|
+
<script src="{{ 'runwell-bundle-system.js' | asset_url }}" defer="defer"></script>
|
|
86
|
+
|
|
87
|
+
{% schema %}
|
|
88
|
+
{
|
|
89
|
+
"name": "Bundle collection",
|
|
90
|
+
"tag": "section",
|
|
91
|
+
"class": "section-runwell-bundle-collection",
|
|
92
|
+
"settings": [
|
|
93
|
+
{
|
|
94
|
+
"type": "select",
|
|
95
|
+
"id": "mode",
|
|
96
|
+
"label": "Layout mode",
|
|
97
|
+
"options": [
|
|
98
|
+
{ "value": "grid", "label": "Grid (/bundles page)" },
|
|
99
|
+
{ "value": "filter_chip", "label": "Filter chip (collection page)" }
|
|
100
|
+
],
|
|
101
|
+
"default": "grid",
|
|
102
|
+
"info": "Grid: standalone /bundles page (Surface 1). Filter chip: pinned cards + filter on a collection page (Surface 6)."
|
|
103
|
+
},
|
|
104
|
+
{ "type": "header", "content": "Grid mode" },
|
|
105
|
+
{ "type": "checkbox", "id": "show_heading", "label": "Show page heading", "default": true },
|
|
106
|
+
{ "type": "text", "id": "title", "label": "Heading", "default": "Bundles" },
|
|
107
|
+
{ "type": "text", "id": "subline", "label": "Subline", "default": "Curated combinations, save more" },
|
|
108
|
+
{ "type": "checkbox", "id": "feature_first_bundle", "label": "Feature first bundle as hero card", "default": true },
|
|
109
|
+
{ "type": "header", "content": "Filter chip mode" },
|
|
110
|
+
{ "type": "text", "id": "chip_label", "label": "Chip label", "default": "Bundles" },
|
|
111
|
+
{ "type": "header", "content": "Layout" },
|
|
112
|
+
{ "type": "color_scheme", "id": "color_scheme", "label": "Color scheme", "default": "scheme-1" },
|
|
113
|
+
{ "type": "range", "id": "padding_top", "label": "Top padding", "min": 0, "max": 160, "step": 4, "default": 64, "unit": "px" },
|
|
114
|
+
{ "type": "range", "id": "padding_bottom", "label": "Bottom padding", "min": 0, "max": 160, "step": 4, "default": 64, "unit": "px" }
|
|
115
|
+
],
|
|
116
|
+
"presets": [
|
|
117
|
+
{ "name": "Bundle: collection grid", "category": "Runwell", "settings": { "mode": "grid" } },
|
|
118
|
+
{ "name": "Bundle: collection filter chip", "category": "Runwell", "settings": { "mode": "filter_chip" } }
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
{% endschema %}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-home-stacks.liquid.
|
|
3
|
+
Surface 3: home page strip of 3 to 4 featured bundle cards. Editorial
|
|
4
|
+
pacing for new visitors. Merchant picks the bundles via a comma-
|
|
5
|
+
separated handle list; v1.5 can upgrade to a multi-product selector.
|
|
6
|
+
|
|
7
|
+
See _clients/capital-v/lushi/specs/bundle-system/spec.md sections 5, 8.3.
|
|
8
|
+
{%- endcomment -%}
|
|
9
|
+
|
|
10
|
+
{%- if settings.bundle_system__surface_3_home_stacks_enabled == false -%}
|
|
11
|
+
{%- comment -%} Tenant has disabled this surface. {%- endcomment -%}
|
|
12
|
+
{%- else -%}
|
|
13
|
+
{%- assign picked_handles = section.settings.bundle_handles | split: ',' -%}
|
|
14
|
+
{%- assign rendered_count = 0 -%}
|
|
15
|
+
|
|
16
|
+
<section
|
|
17
|
+
class="runwell-bundle-home-stacks runwell-bundle-home-stacks--bg-{{ section.settings.bg_band }} color-{{ section.settings.color_scheme }}"
|
|
18
|
+
style="padding-top: {{ section.settings.padding_top }}px; padding-bottom: {{ section.settings.padding_bottom }}px;"
|
|
19
|
+
>
|
|
20
|
+
<div class="runwell-bundle-home-stacks__inner page-width">
|
|
21
|
+
<p class="runwell-bundle-home-stacks__eyebrow">{{ section.settings.eyebrow }}</p>
|
|
22
|
+
<h2 class="runwell-bundle-home-stacks__heading">{{ section.settings.heading }}</h2>
|
|
23
|
+
<div class="runwell-bundle-home-stacks__cards">
|
|
24
|
+
{%- for raw_handle in picked_handles limit: 4 -%}
|
|
25
|
+
{%- assign handle = raw_handle | strip -%}
|
|
26
|
+
{%- assign bundle_product = all_products[handle] -%}
|
|
27
|
+
{%- if bundle_product != blank -%}
|
|
28
|
+
{% render 'runwell-bundle-card', bundle_product: bundle_product, variant: 'default' %}
|
|
29
|
+
{%- assign rendered_count = rendered_count | plus: 1 -%}
|
|
30
|
+
{%- endif -%}
|
|
31
|
+
{%- endfor -%}
|
|
32
|
+
{%- if rendered_count == 0 -%}
|
|
33
|
+
<p class="runwell-bundle-home-stacks__empty">
|
|
34
|
+
Add bundle product handles in section settings to populate this strip.
|
|
35
|
+
</p>
|
|
36
|
+
{%- endif -%}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</section>
|
|
40
|
+
|
|
41
|
+
{{ 'runwell-bundle-system.css' | asset_url | stylesheet_tag }}
|
|
42
|
+
{%- endif -%}
|
|
43
|
+
|
|
44
|
+
{% schema %}
|
|
45
|
+
{
|
|
46
|
+
"name": "Bundle stacks",
|
|
47
|
+
"tag": "section",
|
|
48
|
+
"class": "section-runwell-bundle-home-stacks",
|
|
49
|
+
"settings": [
|
|
50
|
+
{ "type": "text", "id": "eyebrow", "label": "Eyebrow", "default": "Editor's picks" },
|
|
51
|
+
{ "type": "text", "id": "heading", "label": "Heading", "default": "Curated stacks" },
|
|
52
|
+
{
|
|
53
|
+
"type": "textarea",
|
|
54
|
+
"id": "bundle_handles",
|
|
55
|
+
"label": "Bundle product handles (comma-separated, max 4)",
|
|
56
|
+
"info": "Example: morning-stack, recovery-stack, glow-stack"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"type": "select",
|
|
60
|
+
"id": "bg_band",
|
|
61
|
+
"label": "Background",
|
|
62
|
+
"options": [
|
|
63
|
+
{ "value": "white", "label": "White" },
|
|
64
|
+
{ "value": "oat", "label": "Oat" },
|
|
65
|
+
{ "value": "celadon-tint", "label": "Celadon tint" }
|
|
66
|
+
],
|
|
67
|
+
"default": "white"
|
|
68
|
+
},
|
|
69
|
+
{ "type": "color_scheme", "id": "color_scheme", "label": "Color scheme", "default": "scheme-1" },
|
|
70
|
+
{ "type": "range", "id": "padding_top", "label": "Top padding", "min": 0, "max": 160, "step": 4, "default": 64, "unit": "px" },
|
|
71
|
+
{ "type": "range", "id": "padding_bottom", "label": "Bottom padding", "min": 0, "max": 160, "step": 4, "default": 64, "unit": "px" }
|
|
72
|
+
],
|
|
73
|
+
"presets": [
|
|
74
|
+
{ "name": "Bundle: curated stacks", "category": "Runwell" }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
{% endschema %}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-pdp-banner.liquid.
|
|
3
|
+
Surface 5: subtle single-line banner near the buy box on non-bundle
|
|
4
|
+
PDPs. "Save 17% when bundled. View bundle." Tap routes to the bundle
|
|
5
|
+
PDP. Picks the first matching bundle (highest savings_pct if multiple).
|
|
6
|
+
|
|
7
|
+
See _clients/capital-v/lushi/specs/bundle-system/spec.md sections 5, 8.5.
|
|
8
|
+
{%- endcomment -%}
|
|
9
|
+
|
|
10
|
+
{%- if settings.bundle_system__surface_5_pdp_banner_enabled == false -%}
|
|
11
|
+
{%- comment -%} Tenant has disabled this surface. {%- endcomment -%}
|
|
12
|
+
{%- else -%}
|
|
13
|
+
{%- assign bundle_index = shop.metaobjects.bundle_index.entries.value -%}
|
|
14
|
+
{%- assign matching_handles = '' -%}
|
|
15
|
+
{%- if bundle_index and bundle_index.products -%}
|
|
16
|
+
{%- assign matching_handles = bundle_index.products[product.handle] -%}
|
|
17
|
+
{%- endif -%}
|
|
18
|
+
|
|
19
|
+
{%- if matching_handles and matching_handles.size > 0 -%}
|
|
20
|
+
{%- assign bundle_handle = matching_handles | first -%}
|
|
21
|
+
{%- assign bundle_product = all_products[bundle_handle] -%}
|
|
22
|
+
{%- if bundle_product != blank -%}
|
|
23
|
+
{%- assign savings_pct = bundle_product.metafields.runwell.bundle_savings_pct.value | default: 15 -%}
|
|
24
|
+
{%- assign savings_amount = 0 -%}
|
|
25
|
+
{%- assign template = section.settings.copy_template | default: settings.bundle_system__surface_5_copy_template | default: 'Save {savings_pct}% when bundled' -%}
|
|
26
|
+
{%- assign copy = template | replace: '{savings_pct}', savings_pct | replace: '{savings_amount}', savings_amount -%}
|
|
27
|
+
|
|
28
|
+
<a class="runwell-bundle-pdp-banner" href="{{ bundle_product.url }}" data-bundle-handle="{{ bundle_handle }}">
|
|
29
|
+
<span class="runwell-bundle-pdp-banner__copy">{{ copy }}</span>
|
|
30
|
+
<span class="runwell-bundle-pdp-banner__chevron" aria-hidden="true">›</span>
|
|
31
|
+
</a>
|
|
32
|
+
|
|
33
|
+
{{ 'runwell-bundle-system.css' | asset_url | stylesheet_tag }}
|
|
34
|
+
{%- endif -%}
|
|
35
|
+
{%- endif -%}
|
|
36
|
+
{%- endif -%}
|
|
37
|
+
|
|
38
|
+
{% schema %}
|
|
39
|
+
{
|
|
40
|
+
"name": "Bundle banner",
|
|
41
|
+
"tag": "section",
|
|
42
|
+
"class": "section-runwell-bundle-pdp-banner",
|
|
43
|
+
"settings": [
|
|
44
|
+
{ "type": "text", "id": "copy_template", "label": "Copy template", "default": "Save {savings_pct}% when bundled", "info": "Use {savings_pct} or {savings_amount} placeholders. Leave blank to use the site-wide default." }
|
|
45
|
+
],
|
|
46
|
+
"presets": [
|
|
47
|
+
{ "name": "Bundle: PDP banner", "category": "Runwell" }
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
{% endschema %}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-pdp-pairs-with.liquid.
|
|
3
|
+
Surface 2: PDP "Pairs well with" widget. Renders 1 to N bundle cards
|
|
4
|
+
on non-bundle PDPs when the current product appears in at least one
|
|
5
|
+
bundle. Uses the bundle_index shop metaobject for fast reverse lookup
|
|
6
|
+
(one read).
|
|
7
|
+
|
|
8
|
+
Self-suppresses (renders nothing) if no bundles match.
|
|
9
|
+
See _clients/capital-v/lushi/specs/bundle-system/spec.md sections 5, 7.
|
|
10
|
+
{%- endcomment -%}
|
|
11
|
+
|
|
12
|
+
{%- if settings.bundle_system__surface_2_pdp_pairs_with_enabled == false -%}
|
|
13
|
+
{%- comment -%} Tenant has disabled this surface. {%- endcomment -%}
|
|
14
|
+
{%- else -%}
|
|
15
|
+
{%- assign bundle_index = shop.metaobjects.bundle_index.entries.value -%}
|
|
16
|
+
{%- assign matching_handles = '' -%}
|
|
17
|
+
{%- if bundle_index and bundle_index.products -%}
|
|
18
|
+
{%- assign matching_handles = bundle_index.products[product.handle] -%}
|
|
19
|
+
{%- endif -%}
|
|
20
|
+
|
|
21
|
+
{%- if matching_handles and matching_handles.size > 0 -%}
|
|
22
|
+
<section
|
|
23
|
+
class="runwell-bundle-pdp-pairs-with color-{{ section.settings.color_scheme }}"
|
|
24
|
+
data-product-handle="{{ product.handle }}"
|
|
25
|
+
style="padding-top: {{ section.settings.padding_top }}px; padding-bottom: {{ section.settings.padding_bottom }}px;"
|
|
26
|
+
>
|
|
27
|
+
<div class="runwell-bundle-pdp-pairs-with__inner page-width">
|
|
28
|
+
<p class="runwell-bundle-pdp-pairs-with__eyebrow">{{ section.settings.eyebrow }}</p>
|
|
29
|
+
<h3 class="runwell-bundle-pdp-pairs-with__heading">{{ section.settings.heading }}</h3>
|
|
30
|
+
<div class="runwell-bundle-pdp-pairs-with__cards" data-runwell-card-scroll>
|
|
31
|
+
{%- assign max_cards = section.settings.max_cards | plus: 0 | default: 2 -%}
|
|
32
|
+
{%- for handle in matching_handles limit: max_cards -%}
|
|
33
|
+
{%- assign bundle_product = all_products[handle] -%}
|
|
34
|
+
{%- if bundle_product != blank -%}
|
|
35
|
+
{% render 'runwell-bundle-card', bundle_product: bundle_product, variant: 'compact' %}
|
|
36
|
+
{%- endif -%}
|
|
37
|
+
{%- endfor -%}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
41
|
+
|
|
42
|
+
{{ 'runwell-bundle-system.css' | asset_url | stylesheet_tag }}
|
|
43
|
+
{%- endif -%}
|
|
44
|
+
{%- endif -%}
|
|
45
|
+
|
|
46
|
+
{% schema %}
|
|
47
|
+
{
|
|
48
|
+
"name": "Bundle pairs-with",
|
|
49
|
+
"tag": "section",
|
|
50
|
+
"class": "section-runwell-bundle-pdp-pairs-with",
|
|
51
|
+
"settings": [
|
|
52
|
+
{ "type": "text", "id": "eyebrow", "label": "Eyebrow", "default": "Pairs well with" },
|
|
53
|
+
{ "type": "text", "id": "heading", "label": "Heading", "default": "Complete the routine" },
|
|
54
|
+
{
|
|
55
|
+
"type": "select",
|
|
56
|
+
"id": "max_cards",
|
|
57
|
+
"label": "Max bundle cards",
|
|
58
|
+
"options": [
|
|
59
|
+
{ "value": "1", "label": "1" },
|
|
60
|
+
{ "value": "2", "label": "2" }
|
|
61
|
+
],
|
|
62
|
+
"default": "2"
|
|
63
|
+
},
|
|
64
|
+
{ "type": "color_scheme", "id": "color_scheme", "label": "Color scheme", "default": "scheme-1" },
|
|
65
|
+
{ "type": "range", "id": "padding_top", "label": "Top padding", "min": 0, "max": 100, "step": 4, "default": 32, "unit": "px" },
|
|
66
|
+
{ "type": "range", "id": "padding_bottom", "label": "Bottom padding", "min": 0, "max": 100, "step": 4, "default": 32, "unit": "px" }
|
|
67
|
+
],
|
|
68
|
+
"presets": [
|
|
69
|
+
{ "name": "Bundle: pairs well with", "category": "Runwell" }
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
{% endschema %}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-pdp.liquid.
|
|
3
|
+
Bundle PDP section. Used on templates/product.bundle.json (auto-assigned
|
|
4
|
+
to products with the runwell.bundle_mode metafield set). Routes to a
|
|
5
|
+
mode-specific snippet based on bundle_mode.
|
|
6
|
+
|
|
7
|
+
See _clients/capital-v/lushi/specs/bundle-system/spec.md sections 3, 5.
|
|
8
|
+
{%- endcomment -%}
|
|
9
|
+
|
|
10
|
+
{%- comment -%} v2: render runwell-subscription-picker here when bundle_subscription_enabled. Per BS-13 the subscription_* metafields ship in v1 inactive so v2 wires without a schema migration. {%- endcomment -%}
|
|
11
|
+
|
|
12
|
+
{% render 'runwell-bundle-data', product: product %}
|
|
13
|
+
|
|
14
|
+
<section
|
|
15
|
+
class="runwell-bundle-system runwell-bundle-system--mode-{{ bundle_mode | replace: '_', '-' }} color-{{ section.settings.color_scheme }}"
|
|
16
|
+
style="padding-top: {{ section.settings.padding_top }}px; padding-bottom: {{ section.settings.padding_bottom }}px;"
|
|
17
|
+
>
|
|
18
|
+
<div class="runwell-bundle-system__inner page-width">
|
|
19
|
+
<div class="runwell-bundle-system__gallery">
|
|
20
|
+
{%- if product.featured_image -%}
|
|
21
|
+
{{ product.featured_image | image_url: width: 800 | image_tag:
|
|
22
|
+
loading: 'eager',
|
|
23
|
+
width: product.featured_image.width,
|
|
24
|
+
height: product.featured_image.height,
|
|
25
|
+
sizes: '(min-width: 1024px) 50vw, 100vw',
|
|
26
|
+
class: 'runwell-bundle-system__gallery-image'
|
|
27
|
+
}}
|
|
28
|
+
{%- endif -%}
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="runwell-bundle-system__details">
|
|
32
|
+
{%- if section.settings.sale_prefix != blank -%}
|
|
33
|
+
<p class="runwell-bundle-system__sale-prefix">{{ section.settings.sale_prefix }}</p>
|
|
34
|
+
{%- endif -%}
|
|
35
|
+
|
|
36
|
+
<h1 class="runwell-bundle-system__title">{{ product.title }}</h1>
|
|
37
|
+
|
|
38
|
+
{%- if product.description != blank -%}
|
|
39
|
+
<div class="runwell-bundle-system__description rte">{{ product.description }}</div>
|
|
40
|
+
{%- endif -%}
|
|
41
|
+
|
|
42
|
+
{%- if bundle_mode == 'quantity_tiers' -%}
|
|
43
|
+
{% render 'runwell-bundle-quantity-tiers',
|
|
44
|
+
product: product,
|
|
45
|
+
bundle_mode: bundle_mode,
|
|
46
|
+
bundle_pricing_model: bundle_pricing_model,
|
|
47
|
+
bundle_quantity_tiers: bundle_quantity_tiers,
|
|
48
|
+
section: section
|
|
49
|
+
%}
|
|
50
|
+
{%- elsif bundle_mode == 'multi_product' or bundle_mode == 'mix_match' -%}
|
|
51
|
+
{% render 'runwell-bundle-multi-product',
|
|
52
|
+
product: product,
|
|
53
|
+
bundle_mode: bundle_mode,
|
|
54
|
+
bundle_pricing_model: bundle_pricing_model,
|
|
55
|
+
bundle_components: bundle_components,
|
|
56
|
+
bundle_subtotal: bundle_subtotal,
|
|
57
|
+
bundle_price: bundle_price,
|
|
58
|
+
bundle_savings_amount: bundle_savings_amount,
|
|
59
|
+
bundle_savings_pct: bundle_savings_pct
|
|
60
|
+
%}
|
|
61
|
+
{%- endif -%}
|
|
62
|
+
|
|
63
|
+
{%- if bundle_fomo_mode != 'none' and bundle_fomo_mode != blank -%}
|
|
64
|
+
{% render 'runwell-bundle-fomo',
|
|
65
|
+
bundle_fomo_mode: bundle_fomo_mode,
|
|
66
|
+
bundle_fomo_cycle_days: bundle_fomo_cycle_days,
|
|
67
|
+
bundle_fomo_stock_count: bundle_fomo_stock_count
|
|
68
|
+
%}
|
|
69
|
+
{%- endif -%}
|
|
70
|
+
|
|
71
|
+
{%- if bundle_free_gift_enabled -%}
|
|
72
|
+
{% render 'runwell-bundle-free-gift',
|
|
73
|
+
bundle_free_gift_handle: bundle_free_gift_handle
|
|
74
|
+
%}
|
|
75
|
+
{%- endif -%}
|
|
76
|
+
|
|
77
|
+
{%- if bundle_cross_supplier and bundle_supplier_count > 1 -%}
|
|
78
|
+
{% render 'runwell-bundle-cross-supplier',
|
|
79
|
+
bundle_supplier_count: bundle_supplier_count
|
|
80
|
+
%}
|
|
81
|
+
{%- endif -%}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</section>
|
|
85
|
+
|
|
86
|
+
{{ 'runwell-bundle-system.css' | asset_url | stylesheet_tag }}
|
|
87
|
+
<script src="{{ 'runwell-bundle-system.js' | asset_url }}" defer="defer"></script>
|
|
88
|
+
|
|
89
|
+
{% schema %}
|
|
90
|
+
{
|
|
91
|
+
"name": "Bundle PDP",
|
|
92
|
+
"tag": "section",
|
|
93
|
+
"class": "section-runwell-bundle-pdp",
|
|
94
|
+
"settings": [
|
|
95
|
+
{ "type": "text", "id": "sale_prefix", "label": "Sale prefix (above title)", "default": "Limited time offer" },
|
|
96
|
+
{ "type": "color_scheme", "id": "color_scheme", "label": "Color scheme", "default": "scheme-1" },
|
|
97
|
+
{ "type": "range", "id": "padding_top", "label": "Top padding", "min": 0, "max": 100, "step": 4, "default": 40, "unit": "px" },
|
|
98
|
+
{ "type": "range", "id": "padding_bottom", "label": "Bottom padding", "min": 0, "max": 100, "step": 4, "default": 40, "unit": "px" }
|
|
99
|
+
],
|
|
100
|
+
"presets": [
|
|
101
|
+
{ "name": "Bundle PDP", "category": "Runwell" }
|
|
102
|
+
],
|
|
103
|
+
"templates": ["product.bundle"]
|
|
104
|
+
}
|
|
105
|
+
{% endschema %}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Theme customizer settings patch. runwell-shopify sync appends this group to tenant config/settings_schema.json. Site-wide defaults; section-level overrides live in each section's schema.",
|
|
3
|
+
"spec_ref": "_clients/capital-v/lushi/specs/bundle-system/spec.md#10-settings-schema-for-theme-customizer",
|
|
4
|
+
"name": "Bundle system",
|
|
5
|
+
"settings": [
|
|
6
|
+
{ "type": "header", "content": "Display surfaces" },
|
|
7
|
+
{ "type": "checkbox", "id": "bundle_system__surface_1_collection_page_enabled", "label": "/bundles collection page", "default": true },
|
|
8
|
+
{ "type": "checkbox", "id": "bundle_system__surface_2_pdp_pairs_with_enabled", "label": "PDP 'Pairs well with' widget", "default": true },
|
|
9
|
+
{ "type": "checkbox", "id": "bundle_system__surface_3_home_stacks_enabled", "label": "Home page curated stacks", "default": true },
|
|
10
|
+
{ "type": "checkbox", "id": "bundle_system__surface_4_cart_drawer_xsell_enabled", "label": "Cart drawer bundle cross-sell", "default": true },
|
|
11
|
+
{ "type": "checkbox", "id": "bundle_system__surface_5_pdp_banner_enabled", "label": "PDP bundle banner", "default": true },
|
|
12
|
+
{ "type": "checkbox", "id": "bundle_system__surface_6_collection_filter_enabled", "label": "Collection page bundles filter", "default": false },
|
|
13
|
+
{ "type": "header", "content": "Default copy" },
|
|
14
|
+
{ "type": "text", "id": "bundle_system__surface_2_eyebrow", "label": "Surface 2 eyebrow", "default": "Pairs well with" },
|
|
15
|
+
{ "type": "text", "id": "bundle_system__surface_2_heading", "label": "Surface 2 heading", "default": "Complete the routine" },
|
|
16
|
+
{ "type": "text", "id": "bundle_system__surface_3_eyebrow", "label": "Surface 3 eyebrow", "default": "Editor's picks" },
|
|
17
|
+
{ "type": "text", "id": "bundle_system__surface_3_heading", "label": "Surface 3 heading", "default": "Curated stacks" },
|
|
18
|
+
{ "type": "text", "id": "bundle_system__surface_4_eyebrow", "label": "Surface 4 eyebrow", "default": "Complete the stack" },
|
|
19
|
+
{ "type": "text", "id": "bundle_system__surface_4_cta", "label": "Surface 4 CTA", "default": "Add bundle and save" },
|
|
20
|
+
{ "type": "text", "id": "bundle_system__surface_5_copy_template", "label": "Surface 5 copy template", "default": "Save {savings_pct}% when bundled" },
|
|
21
|
+
{ "type": "text", "id": "bundle_system__cross_supplier_disclosure", "label": "Cross-supplier disclosure", "default": "This bundle ships in {n} packages." },
|
|
22
|
+
{ "type": "header", "content": "Layout" },
|
|
23
|
+
{ "type": "range", "id": "bundle_system__home_strip_position", "label": "Home strip position (1-10)", "min": 1, "max": 10, "step": 1, "default": 3 }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-card.liquid.
|
|
3
|
+
Shared bundle card UI used by Surfaces 1, 2, 3, 4, 6.
|
|
4
|
+
|
|
5
|
+
Inputs:
|
|
6
|
+
bundle_product (the bundle product to render; required)
|
|
7
|
+
variant ('compact' | 'default' | 'hero'; default 'default')
|
|
8
|
+
|
|
9
|
+
Renders a self-contained card linking to /products/<bundle_handle>.
|
|
10
|
+
Loads the bundle's metafields locally via runwell-bundle-data so the
|
|
11
|
+
card has access to savings, supplier count, and component count.
|
|
12
|
+
{%- endcomment -%}
|
|
13
|
+
|
|
14
|
+
{%- if bundle_product != blank -%}
|
|
15
|
+
{%- assign card_variant = variant | default: 'default' -%}
|
|
16
|
+
{%- assign product = bundle_product -%}
|
|
17
|
+
{% render 'runwell-bundle-data', product: bundle_product %}
|
|
18
|
+
{%- assign component_count = 0 -%}
|
|
19
|
+
{%- if bundle_components and bundle_components.size > 0 -%}
|
|
20
|
+
{%- assign component_count = bundle_components.size -%}
|
|
21
|
+
{%- endif -%}
|
|
22
|
+
|
|
23
|
+
<a
|
|
24
|
+
href="{{ bundle_product.url }}"
|
|
25
|
+
class="runwell-bundle-card runwell-bundle-card--{{ card_variant }}"
|
|
26
|
+
data-bundle-handle="{{ bundle_product.handle }}"
|
|
27
|
+
>
|
|
28
|
+
<div class="runwell-bundle-card__media">
|
|
29
|
+
{%- if bundle_product.featured_image -%}
|
|
30
|
+
{{ bundle_product.featured_image | image_url: width: 600 | image_tag:
|
|
31
|
+
width: 300,
|
|
32
|
+
height: 300,
|
|
33
|
+
loading: 'lazy',
|
|
34
|
+
class: 'runwell-bundle-card__image',
|
|
35
|
+
alt: bundle_product.title,
|
|
36
|
+
sizes: '(min-width: 1024px) 25vw, 50vw'
|
|
37
|
+
}}
|
|
38
|
+
{%- endif -%}
|
|
39
|
+
|
|
40
|
+
{%- if bundle_savings_pct > 0 and card_variant != 'compact' -%}
|
|
41
|
+
<span class="runwell-bundle-card__badge">Save {{ bundle_savings_pct }}%</span>
|
|
42
|
+
{%- endif -%}
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="runwell-bundle-card__body">
|
|
46
|
+
<h3 class="runwell-bundle-card__title">{{ bundle_product.title }}</h3>
|
|
47
|
+
|
|
48
|
+
{%- if component_count > 0 and card_variant != 'compact' -%}
|
|
49
|
+
<p class="runwell-bundle-card__meta">
|
|
50
|
+
{{ component_count }}{% if component_count == 1 %} item{% else %} items{% endif %}
|
|
51
|
+
{%- if bundle_cross_supplier %} · ships in {{ bundle_supplier_count }} packages{%- endif -%}
|
|
52
|
+
</p>
|
|
53
|
+
{%- endif -%}
|
|
54
|
+
|
|
55
|
+
<div class="runwell-bundle-card__price-row">
|
|
56
|
+
<span class="runwell-bundle-card__price">{{ bundle_price | money }}</span>
|
|
57
|
+
{%- if bundle_subtotal > bundle_price -%}
|
|
58
|
+
<span class="runwell-bundle-card__strikethrough">{{ bundle_subtotal | money }}</span>
|
|
59
|
+
{%- endif -%}
|
|
60
|
+
{%- if bundle_savings_pct > 0 and card_variant == 'compact' -%}
|
|
61
|
+
<span class="runwell-bundle-card__badge runwell-bundle-card__badge--inline">Save {{ bundle_savings_pct }}%</span>
|
|
62
|
+
{%- endif -%}
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
{%- if card_variant == 'hero' or card_variant == 'default' -%}
|
|
66
|
+
<span class="runwell-bundle-card__cta button button--secondary">View bundle</span>
|
|
67
|
+
{%- endif -%}
|
|
68
|
+
</div>
|
|
69
|
+
</a>
|
|
70
|
+
{%- endif -%}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-cross-supplier.liquid.
|
|
3
|
+
Customer-facing disclosure when a bundle ships from multiple suppliers.
|
|
4
|
+
Copy template comes from the theme customizer setting
|
|
5
|
+
bundle_system__cross_supplier_disclosure (default: "This bundle ships
|
|
6
|
+
in {n} packages."), with {n} replaced by bundle_supplier_count.
|
|
7
|
+
|
|
8
|
+
Inputs:
|
|
9
|
+
bundle_supplier_count
|
|
10
|
+
{%- endcomment -%}
|
|
11
|
+
|
|
12
|
+
{%- assign template = settings.bundle_system__cross_supplier_disclosure | default: 'This bundle ships in {n} packages.' -%}
|
|
13
|
+
{%- assign disclosure = template | replace: '{n}', bundle_supplier_count -%}
|
|
14
|
+
|
|
15
|
+
<p class="runwell-bundle-system__cross-supplier" role="note">
|
|
16
|
+
<span class="runwell-bundle-system__cross-supplier-icon" aria-hidden="true">i</span>
|
|
17
|
+
<span class="runwell-bundle-system__cross-supplier-text">{{ disclosure }}</span>
|
|
18
|
+
</p>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-data.liquid.
|
|
3
|
+
Single read point for all runwell.bundle_* product metafields. Other
|
|
4
|
+
snippets and sections read the bundle_* Liquid variables this snippet
|
|
5
|
+
emits. Liquid has no first-class object literal so we emit flat vars
|
|
6
|
+
(bundle_mode, bundle_quantity_tiers, etc.) into the parent scope.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
{% render 'runwell-bundle-data', product: product %}
|
|
10
|
+
{{ bundle_mode }}
|
|
11
|
+
{% for tier in bundle_quantity_tiers %} ... {% endfor %}
|
|
12
|
+
|
|
13
|
+
See _clients/capital-v/lushi/specs/bundle-system/spec.md sections 2.1-2.2.
|
|
14
|
+
{%- endcomment -%}
|
|
15
|
+
|
|
16
|
+
{%- assign mf = product.metafields.runwell -%}
|
|
17
|
+
|
|
18
|
+
{%- assign bundle_mode = mf.bundle_mode.value | default: 'multi_product' -%}
|
|
19
|
+
{%- assign bundle_pricing_model = mf.bundle_pricing_model.value | default: 'fixed_price' -%}
|
|
20
|
+
{%- assign bundle_pricing_value = mf.bundle_pricing_value.value -%}
|
|
21
|
+
{%- assign bundle_components = mf.bundle_components.value -%}
|
|
22
|
+
{%- assign bundle_quantity_tiers = mf.bundle_quantity_tiers.value -%}
|
|
23
|
+
{%- assign bundle_show_in_catalog = mf.bundle_show_in_catalog.value | default: true -%}
|
|
24
|
+
{%- assign bundle_surfaces_enabled = mf.bundle_surfaces_enabled.value -%}
|
|
25
|
+
{%- assign bundle_copy = mf.bundle_copy.value -%}
|
|
26
|
+
{%- assign bundle_free_gift_enabled = mf.bundle_free_gift_enabled.value | default: false -%}
|
|
27
|
+
{%- assign bundle_free_gift_handle = mf.bundle_free_gift_handle.value | default: '' -%}
|
|
28
|
+
{%- assign bundle_fomo_mode = mf.bundle_fomo_mode.value | default: 'none' -%}
|
|
29
|
+
{%- assign bundle_fomo_cycle_days = mf.bundle_fomo_cycle_days.value | default: 30 -%}
|
|
30
|
+
{%- assign bundle_fomo_stock_count = mf.bundle_fomo_stock_count.value | default: 0 -%}
|
|
31
|
+
{%- assign bundle_cross_supplier = mf.bundle_cross_supplier.value | default: false -%}
|
|
32
|
+
{%- assign bundle_supplier_count = mf.bundle_supplier_count.value | default: 1 -%}
|
|
33
|
+
{%- assign bundle_savings_pct_pre = mf.bundle_savings_pct.value -%}
|
|
34
|
+
|
|
35
|
+
{%- comment -%} Compute subtotal for multi_product mode by walking components. {%- endcomment -%}
|
|
36
|
+
{%- assign bundle_subtotal = 0 -%}
|
|
37
|
+
{%- if bundle_components and bundle_components.size > 0 -%}
|
|
38
|
+
{%- for c in bundle_components -%}
|
|
39
|
+
{%- assign comp_product = all_products[c.product_handle] -%}
|
|
40
|
+
{%- assign comp_qty = c.qty | default: 1 -%}
|
|
41
|
+
{%- assign comp_line = comp_product.price | times: comp_qty -%}
|
|
42
|
+
{%- assign bundle_subtotal = bundle_subtotal | plus: comp_line -%}
|
|
43
|
+
{%- endfor -%}
|
|
44
|
+
{%- endif -%}
|
|
45
|
+
|
|
46
|
+
{%- assign bundle_price = product.price -%}
|
|
47
|
+
{%- assign bundle_savings_amount = 0 -%}
|
|
48
|
+
{%- if bundle_subtotal > bundle_price -%}
|
|
49
|
+
{%- assign bundle_savings_amount = bundle_subtotal | minus: bundle_price -%}
|
|
50
|
+
{%- endif -%}
|
|
51
|
+
|
|
52
|
+
{%- assign bundle_savings_pct = 0 -%}
|
|
53
|
+
{%- if bundle_savings_pct_pre -%}
|
|
54
|
+
{%- assign bundle_savings_pct = bundle_savings_pct_pre -%}
|
|
55
|
+
{%- elsif bundle_subtotal > 0 -%}
|
|
56
|
+
{%- assign bundle_savings_pct = bundle_savings_amount | times: 100 | divided_by: bundle_subtotal -%}
|
|
57
|
+
{%- endif -%}
|
|
58
|
+
|
|
59
|
+
{%- comment -%}
|
|
60
|
+
v2 only fields (BS-13). Parsed but unused in v1.
|
|
61
|
+
bundle_subscription_enabled, bundle_subscription_interval,
|
|
62
|
+
bundle_subscription_discount_pct, bundle_subscription_badge_copy.
|
|
63
|
+
{%- endcomment -%}
|
|
64
|
+
{%- assign bundle_subscription_enabled = mf.subscription_enabled.value | default: false -%}
|
|
65
|
+
{%- assign bundle_subscription_interval = mf.subscription_interval.value -%}
|
|
66
|
+
{%- assign bundle_subscription_discount_pct = mf.subscription_discount_pct.value -%}
|
|
67
|
+
{%- assign bundle_subscription_badge_copy = mf.subscription_badge_copy.value | default: '' -%}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-fomo.liquid.
|
|
3
|
+
Countdown ("ends in N days") and scarcity ("X left") strip. Mode driven
|
|
4
|
+
by bundle_fomo_mode metafield: 'discount' | 'scarcity' | 'both' | 'none'.
|
|
5
|
+
|
|
6
|
+
Inputs:
|
|
7
|
+
bundle_fomo_mode
|
|
8
|
+
bundle_fomo_cycle_days
|
|
9
|
+
bundle_fomo_stock_count
|
|
10
|
+
{%- endcomment -%}
|
|
11
|
+
|
|
12
|
+
<div
|
|
13
|
+
class="runwell-bundle-system__fomo"
|
|
14
|
+
data-runwell-fomo
|
|
15
|
+
data-fomo-mode="{{ bundle_fomo_mode }}"
|
|
16
|
+
data-fomo-cycle-days="{{ bundle_fomo_cycle_days }}"
|
|
17
|
+
>
|
|
18
|
+
{%- if bundle_fomo_mode == 'discount' or bundle_fomo_mode == 'both' -%}
|
|
19
|
+
<p class="runwell-bundle-system__fomo-countdown">
|
|
20
|
+
<span class="runwell-bundle-system__fomo-label">Offer ends in</span>
|
|
21
|
+
<span class="runwell-bundle-system__fomo-time" data-runwell-fomo-time>...</span>
|
|
22
|
+
</p>
|
|
23
|
+
{%- endif -%}
|
|
24
|
+
|
|
25
|
+
{%- if bundle_fomo_mode == 'scarcity' or bundle_fomo_mode == 'both' -%}
|
|
26
|
+
{%- if bundle_fomo_stock_count > 0 -%}
|
|
27
|
+
<p class="runwell-bundle-system__fomo-scarcity">
|
|
28
|
+
Only <strong>{{ bundle_fomo_stock_count }}</strong> left at this price.
|
|
29
|
+
</p>
|
|
30
|
+
{%- endif -%}
|
|
31
|
+
{%- endif -%}
|
|
32
|
+
</div>
|