@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,188 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
Runwell product-trio-medvi.
|
|
3
|
+
|
|
4
|
+
3-product showcase: 3 product images in a fan layout with the center
|
|
5
|
+
product foregrounded; single soft-corner copy panel beside, holding
|
|
6
|
+
one short headline. Hero anchor for a product line.
|
|
7
|
+
|
|
8
|
+
Lineage: extracted from home.medvi.org (Framer label "3 Cards / Pill
|
|
9
|
+
Image Group"), generalised to Runwell brand tokens.
|
|
10
|
+
{%- endcomment -%}
|
|
11
|
+
|
|
12
|
+
{{ 'runwell-product-trio-medvi.css' | asset_url | stylesheet_tag }}
|
|
13
|
+
|
|
14
|
+
{%- liquid
|
|
15
|
+
assign layout = section.settings.layout | default: 'products-left'
|
|
16
|
+
assign bg_band = section.settings.bg_band | default: 'white'
|
|
17
|
+
assign panel_bg = section.settings.panel_bg | default: 'var(--runwell-oat)'
|
|
18
|
+
-%}
|
|
19
|
+
|
|
20
|
+
<section
|
|
21
|
+
class="runwell-product-trio-medvi runwell-product-trio-medvi--{{ layout }} runwell-product-trio-medvi--bg-{{ bg_band }}"
|
|
22
|
+
>
|
|
23
|
+
<div class="runwell-product-trio-medvi__inner">
|
|
24
|
+
|
|
25
|
+
<div class="runwell-product-trio-medvi__products">
|
|
26
|
+
<div class="runwell-product-trio-medvi__product runwell-product-trio-medvi__product--left">
|
|
27
|
+
{%- if section.settings.product_image_left != blank -%}
|
|
28
|
+
<img
|
|
29
|
+
src="{{ section.settings.product_image_left | image_url: width: 600 }}"
|
|
30
|
+
alt="{{ section.settings.product_image_left.alt | default: '' | escape }}"
|
|
31
|
+
width="{{ section.settings.product_image_left.width }}"
|
|
32
|
+
height="{{ section.settings.product_image_left.height }}"
|
|
33
|
+
loading="lazy"
|
|
34
|
+
>
|
|
35
|
+
{%- elsif section.settings.product_image_left_asset != blank -%}
|
|
36
|
+
<img
|
|
37
|
+
src="{{ section.settings.product_image_left_asset | asset_url }}"
|
|
38
|
+
alt=""
|
|
39
|
+
width="600"
|
|
40
|
+
height="800"
|
|
41
|
+
loading="lazy"
|
|
42
|
+
>
|
|
43
|
+
{%- endif -%}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="runwell-product-trio-medvi__product runwell-product-trio-medvi__product--center">
|
|
47
|
+
{%- if section.settings.product_image_center != blank -%}
|
|
48
|
+
<img
|
|
49
|
+
src="{{ section.settings.product_image_center | image_url: width: 800 }}"
|
|
50
|
+
alt="{{ section.settings.product_image_center.alt | default: '' | escape }}"
|
|
51
|
+
width="{{ section.settings.product_image_center.width }}"
|
|
52
|
+
height="{{ section.settings.product_image_center.height }}"
|
|
53
|
+
loading="lazy"
|
|
54
|
+
>
|
|
55
|
+
{%- elsif section.settings.product_image_center_asset != blank -%}
|
|
56
|
+
<img
|
|
57
|
+
src="{{ section.settings.product_image_center_asset | asset_url }}"
|
|
58
|
+
alt=""
|
|
59
|
+
width="800"
|
|
60
|
+
height="1000"
|
|
61
|
+
loading="lazy"
|
|
62
|
+
>
|
|
63
|
+
{%- endif -%}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div class="runwell-product-trio-medvi__product runwell-product-trio-medvi__product--right">
|
|
67
|
+
{%- if section.settings.product_image_right != blank -%}
|
|
68
|
+
<img
|
|
69
|
+
src="{{ section.settings.product_image_right | image_url: width: 600 }}"
|
|
70
|
+
alt="{{ section.settings.product_image_right.alt | default: '' | escape }}"
|
|
71
|
+
width="{{ section.settings.product_image_right.width }}"
|
|
72
|
+
height="{{ section.settings.product_image_right.height }}"
|
|
73
|
+
loading="lazy"
|
|
74
|
+
>
|
|
75
|
+
{%- elsif section.settings.product_image_right_asset != blank -%}
|
|
76
|
+
<img
|
|
77
|
+
src="{{ section.settings.product_image_right_asset | asset_url }}"
|
|
78
|
+
alt=""
|
|
79
|
+
width="600"
|
|
80
|
+
height="800"
|
|
81
|
+
loading="lazy"
|
|
82
|
+
>
|
|
83
|
+
{%- endif -%}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
{%- if section.settings.panel_heading != blank -%}
|
|
88
|
+
<div
|
|
89
|
+
class="runwell-product-trio-medvi__panel"
|
|
90
|
+
style="background: {{ panel_bg }};"
|
|
91
|
+
>
|
|
92
|
+
<p class="runwell-product-trio-medvi__panel-heading">{{ section.settings.panel_heading }}</p>
|
|
93
|
+
</div>
|
|
94
|
+
{%- endif -%}
|
|
95
|
+
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
|
|
99
|
+
{% schema %}
|
|
100
|
+
{
|
|
101
|
+
"name": "Product trio (medvi)",
|
|
102
|
+
"tag": "section",
|
|
103
|
+
"class": "section-runwell-product-trio-medvi",
|
|
104
|
+
"settings": [
|
|
105
|
+
{
|
|
106
|
+
"type": "header",
|
|
107
|
+
"content": "Products (3 images)"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "image_picker",
|
|
111
|
+
"id": "product_image_left",
|
|
112
|
+
"label": "Left product image",
|
|
113
|
+
"info": "PNG with transparent background recommended."
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"type": "text",
|
|
117
|
+
"id": "product_image_left_asset",
|
|
118
|
+
"label": "Left product image (asset filename)"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"type": "image_picker",
|
|
122
|
+
"id": "product_image_center",
|
|
123
|
+
"label": "Center product image (foregrounded)"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"type": "text",
|
|
127
|
+
"id": "product_image_center_asset",
|
|
128
|
+
"label": "Center product image (asset filename)"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"type": "image_picker",
|
|
132
|
+
"id": "product_image_right",
|
|
133
|
+
"label": "Right product image"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"type": "text",
|
|
137
|
+
"id": "product_image_right_asset",
|
|
138
|
+
"label": "Right product image (asset filename)"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"type": "header",
|
|
142
|
+
"content": "Copy panel"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"type": "text",
|
|
146
|
+
"id": "panel_heading",
|
|
147
|
+
"label": "Panel headline",
|
|
148
|
+
"default": "Doctor-formulated blends designed to support how your body works best."
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"type": "color",
|
|
152
|
+
"id": "panel_bg",
|
|
153
|
+
"label": "Panel background tint",
|
|
154
|
+
"default": "#F5F0EE"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"type": "header",
|
|
158
|
+
"content": "Layout"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"type": "select",
|
|
162
|
+
"id": "layout",
|
|
163
|
+
"label": "Layout",
|
|
164
|
+
"options": [
|
|
165
|
+
{ "value": "products-left", "label": "Products on left" },
|
|
166
|
+
{ "value": "products-right", "label": "Products on right" }
|
|
167
|
+
],
|
|
168
|
+
"default": "products-left"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"type": "select",
|
|
172
|
+
"id": "bg_band",
|
|
173
|
+
"label": "Background band",
|
|
174
|
+
"options": [
|
|
175
|
+
{ "value": "white", "label": "White" },
|
|
176
|
+
{ "value": "oat", "label": "Oat" },
|
|
177
|
+
{ "value": "celadon-tint", "label": "Celadon tint" }
|
|
178
|
+
],
|
|
179
|
+
"default": "white"
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"presets": [
|
|
183
|
+
{
|
|
184
|
+
"name": "Product trio (medvi)"
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
{% endschema %}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# runwell-bundle-system
|
|
2
|
+
|
|
3
|
+
Configurable bundles engine for Runwell Shopify tenants.
|
|
4
|
+
|
|
5
|
+
## Modes
|
|
6
|
+
- Mode A: single-product quantity tiers (Lusha pattern).
|
|
7
|
+
- Mode B: curated multi-product bundles (Lushi pattern).
|
|
8
|
+
- Mode C: mix-and-match / build-your-own (v1.5).
|
|
9
|
+
- Mode D: subscription bundles (v2).
|
|
10
|
+
|
|
11
|
+
## Display surfaces
|
|
12
|
+
1. Dedicated /bundles collection page.
|
|
13
|
+
2. PDP "Pairs well with" widget.
|
|
14
|
+
3. Home page curated stacks.
|
|
15
|
+
4. Cart drawer bundle cross-sell.
|
|
16
|
+
5. PDP bundle banner.
|
|
17
|
+
6. Collection page bundles filter.
|
|
18
|
+
|
|
19
|
+
## Architecture
|
|
20
|
+
Sits on top of Shopify's free first-party Bundles app. Reads per-bundle config from product metafields (namespace: runwell). See spec.md for the data model.
|
|
21
|
+
|
|
22
|
+
## Replaces
|
|
23
|
+
- bundle-builder (deprecated; Lusha migrates in v1.1).
|
|
24
|
+
|
|
25
|
+
## Lineage
|
|
26
|
+
Net-new Runwell module. Spec: `_clients/capital-v/lushi/specs/bundle-system/spec.md`.
|
|
27
|
+
|
|
28
|
+
## Files in this module
|
|
29
|
+
|
|
30
|
+
- `module.json`: module manifest, config schema, admin_steps array.
|
|
31
|
+
- `admin-metafields.json`: source of truth for the 19 product metafields and the `bundle_index` shop metaobject. Source for `runwell-shopify provision-metafields` and merchant manual setup.
|
|
32
|
+
- `settings.json`: theme customizer settings patch. Appended to tenant `config/settings_schema.json` by `runwell-shopify sync`.
|
|
33
|
+
- `sections/`: one Liquid section per display surface (placeholders until BS-2 onwards).
|
|
34
|
+
- `snippets/`: shared bundle UI partials (placeholders until BS-2 onwards).
|
|
35
|
+
- `assets/`: module CSS and JS (placeholders until BS-2 onwards).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Source of truth for runwell.bundle_* product metafield definitions. Mirrors spec.md section 2.1. Read by runwell-shopify provision-metafields (when implemented) and by admin-guide.md for manual setup.",
|
|
3
|
+
"spec_ref": "_clients/capital-v/lushi/specs/bundle-system/spec.md#21-per-bundle-product-metafields",
|
|
4
|
+
"product_metafields": {
|
|
5
|
+
"namespace": "runwell",
|
|
6
|
+
"owner_type": "PRODUCT",
|
|
7
|
+
"definitions": [
|
|
8
|
+
{ "key": "bundle_mode", "name": "Bundle mode", "type": "single_line_text_field", "validations": [{ "name": "choices", "value": "[\"quantity_tiers\",\"multi_product\",\"mix_match\",\"subscription\"]" }] },
|
|
9
|
+
{ "key": "bundle_pricing_model", "name": "Bundle pricing model", "type": "single_line_text_field", "validations": [{ "name": "choices", "value": "[\"tier_quantity\",\"fixed_price\",\"percent_off_subtotal\",\"dollar_off_subtotal\"]" }] },
|
|
10
|
+
{ "key": "bundle_pricing_value", "name": "Bundle pricing value (JSON)", "type": "json", "description": "Shape varies by pricing_model. See spec.md section 2.2." },
|
|
11
|
+
{ "key": "bundle_components", "name": "Bundle components (JSON)", "type": "json", "description": "Required for multi_product / mix_match. Array of {product_handle, qty}." },
|
|
12
|
+
{ "key": "bundle_quantity_tiers", "name": "Bundle quantity tiers (JSON)", "type": "json", "description": "Required for quantity_tiers. Array of {qty, discount_pct}. Mirrors quantity_breaks schema." },
|
|
13
|
+
{ "key": "bundle_show_in_catalog", "name": "Show in main catalog", "type": "boolean", "default": true },
|
|
14
|
+
{ "key": "bundle_surfaces_enabled", "name": "Surfaces enabled (JSON)", "type": "json", "description": "Per-bundle surface allowlist. Array of 1..6. Absent = all enabled at tenant level." },
|
|
15
|
+
{ "key": "bundle_copy", "name": "Per-surface copy (JSON)", "type": "json", "description": "Per-surface eyebrow/heading/cta overrides." },
|
|
16
|
+
{ "key": "bundle_free_gift_enabled", "name": "Free gift enabled", "type": "boolean", "default": false },
|
|
17
|
+
{ "key": "bundle_free_gift_handle", "name": "Free gift product handle", "type": "single_line_text_field" },
|
|
18
|
+
{ "key": "bundle_fomo_mode", "name": "FOMO mode", "type": "single_line_text_field", "validations": [{ "name": "choices", "value": "[\"none\",\"discount\",\"scarcity\",\"both\"]" }] },
|
|
19
|
+
{ "key": "bundle_fomo_cycle_days", "name": "FOMO cycle (days)", "type": "number_integer" },
|
|
20
|
+
{ "key": "bundle_fomo_stock_count", "name": "FOMO stock count", "type": "number_integer" },
|
|
21
|
+
{ "key": "bundle_cross_supplier", "name": "Cross-supplier", "type": "boolean", "default": false },
|
|
22
|
+
{ "key": "bundle_supplier_count", "name": "Supplier count", "type": "number_integer" },
|
|
23
|
+
{ "key": "bundle_savings_pct", "name": "Computed savings percent", "type": "number_decimal", "description": "Precomputed for fast banner / card render. Recomputed by runwell-shopify rebuild-bundle-index." },
|
|
24
|
+
{ "key": "subscription_enabled", "name": "Subscription enabled (v2)", "type": "boolean", "default": false, "v2_only": true },
|
|
25
|
+
{ "key": "subscription_interval", "name": "Subscription interval (JSON, v2)", "type": "json", "v2_only": true },
|
|
26
|
+
{ "key": "subscription_discount_pct", "name": "Subscription discount percent (v2)", "type": "number_decimal", "v2_only": true },
|
|
27
|
+
{ "key": "subscription_badge_copy", "name": "Subscription badge copy (v2)", "type": "single_line_text_field", "v2_only": true }
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"shop_metaobjects": [
|
|
31
|
+
{
|
|
32
|
+
"type": "bundle_index",
|
|
33
|
+
"name": "Bundle index",
|
|
34
|
+
"description": "Forward map (bundles -> components) and reverse map (products -> bundles) used by surfaces 2/4 to avoid N+1 reads. Single instance per shop. Rebuilt by runwell-shopify rebuild-bundle-index or by Shopify Flow on bundle product create/update.",
|
|
35
|
+
"field_definitions": [
|
|
36
|
+
{ "key": "entries", "name": "Entries", "type": "json", "description": "{products: {handle: [bundle_handles]}, bundles: {handle: {components: {handle: qty}}}}" }
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"cross_field_validation": [
|
|
41
|
+
{ "rule": "bundle_quantity_tiers required when bundle_mode == 'quantity_tiers'", "enforced_by": "runwell-shopify qa --bundles" },
|
|
42
|
+
{ "rule": "bundle_components required when bundle_mode in ['multi_product','mix_match']", "enforced_by": "runwell-shopify qa --bundles" },
|
|
43
|
+
{ "rule": "bundle_pricing_value shape matches bundle_pricing_model (see spec.md section 2.2)", "enforced_by": "runwell-shopify qa --bundles" },
|
|
44
|
+
{ "rule": "bundle_free_gift_handle required when bundle_free_gift_enabled == true", "enforced_by": "runwell-shopify qa --bundles" }
|
|
45
|
+
]
|
|
46
|
+
}
|